rethinkdb 2.2.0.4 → 2.3.0.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.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/lib/exc.rb +14 -13
  3. data/lib/func.rb +2 -0
  4. data/lib/net.rb +201 -26
  5. data/lib/ql2.pb.rb +4 -0
  6. data/lib/shim.rb +1 -0
  7. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61203b4912d349374e32f44b3db3b1b66a65345b
4
- data.tar.gz: 3bdc2e9c7f63883392ef703f9ec9e81a257c6f5f
3
+ metadata.gz: 3cc46a96063b3b943304398afd307176d3847889
4
+ data.tar.gz: e0f277c7d8ca4c0d7ac3405cad9c2fadb65d2026
5
5
  SHA512:
6
- metadata.gz: 05c173811f8db6ad995a9e4dae15369ac03727fad9b562ba4c2d2b9352eeb8fb67f4383dc4880b2900e44d022ebbe7484635f255540f15db4213c73d6defff38
7
- data.tar.gz: 3283f2eefd314523dad97e6d1457ac5bc2f10ebaa967631b26aced0ed3e65bb80bf063bea030a85f5624c7df37665667a45be733852a1e30912f457deabf21c5
6
+ metadata.gz: 8c6fbddd6d2063eab25468fcedcab36c97f06fbca90bb8eaf55b5d0f22fcd99e36f6dc658e42963226c073696a066b7392b93717b5e82a0de3c08a707af41282
7
+ data.tar.gz: 6827ef687ed5a9e09c61320a4bf6f77918403a155890c475f9d34279a8f455697fdce4069c69f3c4c4f0bd35d44974f9514607e799be2fbe7dc8f718d74f7447
data/lib/exc.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  module RethinkDB
2
- ReqlError = RqlError = Class.new(RuntimeError)
2
+ RqlError = ReqlError = Class.new(RuntimeError)
3
3
 
4
- ReqlRuntimeError = RqlRuntimeError = Class.new(ReqlError)
5
- ReqlInternalError = RqlInternalError = Class.new(ReqlRuntimeError)
6
- ReqlResourceLimitError = RqlResourceLimitError = Class.new(ReqlRuntimeError)
7
- ReqlQueryLogicError = RqlQueryLogicError = Class.new(ReqlRuntimeError)
8
- ReqlNonExistenceError = RqlNonExistenceError = Class.new(ReqlQueryLogicError)
9
- ReqlAvailabilityError = RqlAvailabilityError = Class.new(ReqlRuntimeError)
10
- ReqlOpFailedError = RqlOpFailedError = Class.new(ReqlAvailabilityError)
11
- ReqlOpIndeterminateError = RqlOpIndeterminateError = Class.new(ReqlAvailabilityError)
12
- ReqlUserError = RqlUserError = Class.new(ReqlRuntimeError)
4
+ RqlRuntimeError = ReqlRuntimeError = Class.new(ReqlError)
5
+ RqlInternalError = ReqlInternalError = Class.new(ReqlRuntimeError)
6
+ RqlResourceLimitError = ReqlResourceLimitError = Class.new(ReqlRuntimeError)
7
+ RqlQueryLogicError = ReqlQueryLogicError = Class.new(ReqlRuntimeError)
8
+ RqlNonExistenceError = ReqlNonExistenceError = Class.new(ReqlQueryLogicError)
9
+ RqlAvailabilityError = ReqlAvailabilityError = Class.new(ReqlRuntimeError)
10
+ RqlOpFailedError = ReqlOpFailedError = Class.new(ReqlAvailabilityError)
11
+ RqlOpIndeterminateError = ReqlOpIndeterminateError = Class.new(ReqlAvailabilityError)
12
+ RqlUserError = ReqlUserError = Class.new(ReqlRuntimeError)
13
+ ReqlPermissionError = Class.new(ReqlRuntimeError)
13
14
 
14
- ReqlDriverError = RqlDriverError = Class.new(ReqlError)
15
- ReqlAuthError = RqlAuthError = Class.new(ReqlDriverError)
16
- ReqlCompileError = RqlCompileError = Class.new(ReqlError)
15
+ RqlDriverError = ReqlDriverError = Class.new(ReqlError)
16
+ RqlAuthError = ReqlAuthError = Class.new(ReqlDriverError)
17
+ RqlCompileError = ReqlCompileError = Class.new(ReqlError)
17
18
  ReqlServerCompileError = Class.new(ReqlCompileError)
18
19
  ReqlDriverCompileError = Class.new(ReqlCompileError)
19
20
  end
data/lib/func.rb CHANGED
@@ -22,6 +22,7 @@ module RethinkDB
22
22
  :insert => 1,
23
23
  :delete => -1,
24
24
  :reduce => -1,
25
+ :fold => -1,
25
26
  :between => 2,
26
27
  :table => -1,
27
28
  :table_create => -1,
@@ -34,6 +35,7 @@ module RethinkDB
34
35
  :during => -1,
35
36
  :orderby => -1,
36
37
  :order_by => -1,
38
+ :union => -1,
37
39
  :group => -1,
38
40
  :iso8601 => -1,
39
41
  :index_create => -1,
data/lib/net.rb CHANGED
@@ -1,10 +1,12 @@
1
+ require 'base64'
2
+ require 'openssl'
1
3
  require 'monitor'
4
+ require 'pp' # This is needed for pretty_inspect
2
5
  require 'set'
6
+ require 'securerandom'
3
7
  require 'socket'
4
8
  require 'thread'
5
9
  require 'timeout'
6
- require 'pp' # This is needed for pretty_inspect
7
- require 'openssl'
8
10
 
9
11
  module RethinkDB
10
12
  module Faux_Abort
@@ -456,6 +458,7 @@ module RethinkDB
456
458
 
457
459
  class Connection
458
460
  include OpenSSL
461
+
459
462
  def auto_reconnect(x=true)
460
463
  @auto_reconnect = x
461
464
  self
@@ -474,7 +477,13 @@ module RethinkDB
474
477
  @host = opts[:host] || "localhost"
475
478
  @port = (opts[:port] || 28015).to_i
476
479
  @default_db = opts[:db]
477
- @auth_key = opts[:auth_key] || ""
480
+ @user = opts[:user] || "admin"
481
+ @user = @user.gsub("=", "=3D").gsub(",","=2C")
482
+ if opts[:password] && opts[:auth_key]
483
+ raise ReqlDriverError, "Cannot specify both a password and an auth key."
484
+ end
485
+ @password = opts[:password] || opts[:auth_key] || ""
486
+ @nonce = SecureRandom.base64(18)
478
487
  @timeout = opts[:timeout].to_i
479
488
  @timeout = 20 if @timeout <= 0
480
489
  @ssl_opts = opts[:ssl] || {}
@@ -490,6 +499,13 @@ module RethinkDB
490
499
  end
491
500
  attr_reader :host, :port, :default_db, :conn_id
492
501
 
502
+ def client_port
503
+ is_open() ? @socket.addr[1] : nil
504
+ end
505
+ def client_address
506
+ is_open() ? @socket.addr[3] : nil
507
+ end
508
+
493
509
  def new_token
494
510
  @token_cnt_mutex.synchronize{@token_cnt += 1}
495
511
  end
@@ -576,10 +592,11 @@ module RethinkDB
576
592
  @mon.synchronize {
577
593
  written = 0
578
594
  while written < packet.length
579
- # Supposedly slice will not copy the array if it goes all the way to the end
580
- # We use IO::syswrite here rather than IO::write because of incompatibilities in
581
- # JRuby regarding filling up the TCP send buffer.
582
- # Reference: https://github.com/rethinkdb/rethinkdb/issues/3795
595
+ # Supposedly slice will not copy the array if it goes all
596
+ # the way to the end We use IO::syswrite here rather than
597
+ # IO::write because of incompatibilities in JRuby regarding
598
+ # filling up the TCP send buffer. Reference:
599
+ # https://github.com/rethinkdb/rethinkdb/issues/3795
583
600
  written += @socket.syswrite(packet.slice(written, packet.length))
584
601
  end
585
602
  }
@@ -645,7 +662,8 @@ module RethinkDB
645
662
  end
646
663
 
647
664
  @@last = nil
648
- @@magic_number = VersionDummy::Version::V0_4
665
+ @@magic_number = VersionDummy::Version::V1_0
666
+ @@protocol_version = 0
649
667
  @@wire_protocol = VersionDummy::Protocol::JSON
650
668
 
651
669
  def debug_socket; @socket; end
@@ -814,6 +832,180 @@ module RethinkDB
814
832
  note_data(token, data)
815
833
  end
816
834
 
835
+ def rcv_json
836
+ response = ""
837
+ while response[-1..-1] != "\0"
838
+ response += @socket.read_exn(1, @timeout)
839
+ end
840
+ begin
841
+ res = JSON.parse(response[0...-1])
842
+ if !res['success']
843
+ msg = "Handshake error (#{res})."
844
+ ecode = res['error_code']
845
+ if ecode && ecode >= 10 && ecode <= 20
846
+ msg = res['error'] if res['error'].to_s != ""
847
+ raise ReqlAuthError, msg
848
+ else
849
+ raise ReqlDriverError, msg
850
+ end
851
+ end
852
+ rescue Exception => e
853
+ if !e.class.ancestors.include?(ReqlDriverError)
854
+ raise ReqlDriverError, "Connection closed by server (#{e})."
855
+ else
856
+ raise e
857
+ end
858
+ end
859
+ return res
860
+ end
861
+
862
+ def send_json(x)
863
+ send(x.to_json + "\0")
864
+ end
865
+
866
+ def check_version(server_info)
867
+ if server_info['min_protocol_version'] > @@protocol_version ||
868
+ server_info['max_protocol_version'] < @@protocol_version
869
+ raise ReqlDriverError, "Version mismatch: Driver uses #{@@protocol_version} "+
870
+ "but server accepts "+
871
+ "[#{server_info['min_version']}, #{server_info['max_version']}]."
872
+ end
873
+ end
874
+
875
+ def check_nonce(server_nonce, nonce)
876
+ if !server_nonce.start_with?(nonce)
877
+ raise ReqlDriverError, "Invalid nonce #{server_nonce} received from server."
878
+ end
879
+ end
880
+
881
+ @@fast_auth_func = lambda {|*args|
882
+ digest = OpenSSL::Digest::SHA256.new
883
+ OpenSSL::PKCS5.pbkdf2_hmac(*args, digest.digest_length, digest)
884
+ }
885
+ @@slow_auth_func = lambda {|password, salt, iter|
886
+ mac = OpenSSL::HMAC.new(password, OpenSSL::Digest::SHA256.new)
887
+ acc = t = mac.update(salt + "\0\0\0\1").digest
888
+ mac.reset
889
+ (iter-1).times{acc = xor(acc, t = mac.update(t).digest); mac.reset}
890
+ res = acc
891
+ }
892
+ @@auth_func = @@fast_auth_func
893
+ @@auth_func_mutex = Mutex.new
894
+
895
+ @@auth_cache = {}
896
+ @@auth_cache_mutex = Mutex.new
897
+
898
+ def pbkdf2_hmac_sha256(*args)
899
+ auth_func = res = nil
900
+ @@auth_cache_mutex.synchronize {
901
+ res = @@auth_cache[args]
902
+ return res if res
903
+ }
904
+
905
+ @@auth_func_mutex.synchronize {
906
+ auth_func = @@auth_func
907
+ }
908
+ begin
909
+ res = auth_func.call(*args)
910
+ rescue NotImplementedError => e
911
+ if auth_func != @@slow_auth_func
912
+ @@auth_func_mutex.synchronize {
913
+ auth_func = @@auth_func = @@slow_auth_func
914
+ }
915
+ res = auth_func.call(*args)
916
+ else
917
+ raise e
918
+ end
919
+ end
920
+
921
+ @@auth_cache_mutex.synchronize {
922
+ @@auth_cache[args] = res
923
+ }
924
+ return res
925
+ end
926
+
927
+ def hmac(*args)
928
+ OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, *args)
929
+ end
930
+
931
+ def sha256(str)
932
+ OpenSSL::Digest.digest("SHA256", str)
933
+ end
934
+
935
+ def self.xor(str1, str2)
936
+ out = str1.dup
937
+ out.bytesize.times {|i|
938
+ out.setbyte(i, out.getbyte(i) ^ str2.getbyte(i))
939
+ }
940
+ return out
941
+ end
942
+
943
+ def const_eq(a, b)
944
+ return false if a.size != b.size
945
+ residue = 0
946
+ a.unpack('C*').zip(b.unpack('C*')).each{|x,y|
947
+ residue |= (x ^ y)
948
+ }
949
+ return residue == 0
950
+ end
951
+
952
+ def check_server_signature_claim(server_signature_claim, server_signature)
953
+ if !const_eq(server_signature_claim, server_signature)
954
+ sig1 = Base64.strict_encode64(server_signature_claim)
955
+ sig2 = Base64.strict_encode64(server_signature)
956
+ raise ReqlAuthError, "Server signature #{sig1} does "+
957
+ "not match expected signature #{sig2}."
958
+ end
959
+ end
960
+
961
+ def do_handshake
962
+ begin
963
+ send([@@magic_number].pack('L<'))
964
+ client_first_message_bare = "n=#{@user},r=#{@nonce}"
965
+ send_json({ protocol_version: @@protocol_version,
966
+ authentication_method: "SCRAM-SHA-256",
967
+ authentication: "n,,#{client_first_message_bare}" })
968
+
969
+ server_version_msg = rcv_json
970
+ check_version(server_version_msg)
971
+
972
+ auth_resp = rcv_json
973
+ server_first_message = auth_resp['authentication']
974
+
975
+ fields = Hash[server_first_message.split(',').map{|x| x.split('=', 2)}]
976
+ server_nonce = fields['r']
977
+
978
+ client_final_message_without_proof = "c=biws,r=#{server_nonce}"
979
+ auth_message = "#{client_first_message_bare},#{server_first_message},"+
980
+ client_final_message_without_proof
981
+ check_nonce(server_nonce, @nonce)
982
+ salt = Base64.decode64(fields['s'])
983
+ iter = fields['i'].to_i
984
+
985
+ salted_password = pbkdf2_hmac_sha256(@password, salt, iter)
986
+
987
+ client_key = hmac(salted_password, "Client Key")
988
+ stored_key = sha256(client_key)
989
+ client_signature = hmac(stored_key, auth_message)
990
+ client_proof = Connection::xor(client_key, client_signature)
991
+ cproof_64 = Base64.strict_encode64(client_proof)
992
+
993
+ msg = "#{client_final_message_without_proof},p=#{cproof_64}"
994
+ send_json({authentication: msg})
995
+
996
+ sig_resp = rcv_json
997
+ fields = Hash[sig_resp['authentication'].split(',').map{|x| x.split('=', 2)}]
998
+ server_signature_claim = Base64::decode64(fields['v'])
999
+ server_key = hmac(salted_password, "Server Key")
1000
+ server_signature = hmac(server_key, auth_message)
1001
+ check_server_signature_claim(server_signature_claim, server_signature)
1002
+ rescue ReqlError => e
1003
+ raise e
1004
+ rescue Exception => e
1005
+ raise ReqlDriverError, "Error during handshake: #{e.inspect} #{e.backtrace}"
1006
+ end
1007
+ end
1008
+
817
1009
  def start_listener
818
1010
  class << @socket
819
1011
  def maybe_timeout(sec=nil, &b)
@@ -829,24 +1021,7 @@ module RethinkDB
829
1021
  }
830
1022
  end
831
1023
  end
832
- send([@@magic_number, @auth_key.size].pack('L<L<') +
833
- @auth_key + [@@wire_protocol].pack('L<'))
834
- response = ""
835
- while response[-1..-1] != "\0"
836
- response += @socket.read_exn(1, @timeout)
837
- end
838
- response = response[0...-1]
839
- if response == "SUCCESS"
840
- # do nothing
841
- elsif response == "ERROR: Incorrect authorization key.\n"
842
- raise ReqlAuthError, "Incorrect authorization key."
843
- else
844
- raise ReqlRuntimeError, "Server dropped connection with message: \"#{response}\""
845
- end
846
-
847
- if @listener
848
- raise ReqlDriverError, "Internal driver error, listener already started."
849
- end
1024
+ do_handshake
850
1025
  @listener = Thread.new {
851
1026
  while true
852
1027
  begin
data/lib/ql2.pb.rb CHANGED
@@ -8,6 +8,7 @@ module RethinkDB
8
8
  V0_2 = 1915781601
9
9
  V0_3 = 1601562686
10
10
  V0_4 = 1074539808
11
+ V1_0 = 885177795
11
12
  end
12
13
 
13
14
  module Protocol
@@ -59,6 +60,7 @@ module RethinkDB
59
60
  OP_FAILED = 4100000
60
61
  OP_INDETERMINATE = 4200000
61
62
  USER = 5000000
63
+ PERMISSION_ERROR = 6000000
62
64
  end
63
65
 
64
66
  module ResponseNote
@@ -140,6 +142,7 @@ module RethinkDB
140
142
  BETWEEN = 182
141
143
  REDUCE = 37
142
144
  MAP = 38
145
+ FOLD = 187
143
146
  FILTER = 39
144
147
  CONCAT_MAP = 40
145
148
  ORDER_BY = 41
@@ -176,6 +179,7 @@ module RethinkDB
176
179
  RECONFIGURE = 176
177
180
  REBALANCE = 179
178
181
  SYNC = 138
182
+ GRANT = 188
179
183
  INDEX_CREATE = 75
180
184
  INDEX_DROP = 76
181
185
  INDEX_LIST = 77
data/lib/shim.rb CHANGED
@@ -72,6 +72,7 @@ module RethinkDB
72
72
  when re::OP_FAILED then raise ReqlOpFailedError, r['r'][0]
73
73
  when re::OP_INDETERMINATE then raise ReqlOpIndeterminateError, r['r'][0]
74
74
  when re::USER then raise ReqlUserError, r['r'][0]
75
+ when re::PERMISSION_ERROR then raise ReqlPermissionError, r['r'][0]
75
76
  else raise ReqlRuntimeError, r['r'][0]
76
77
  end
77
78
  when rt::COMPILE_ERROR then raise ReqlServerCompileError, r['r'][0]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rethinkdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0.4
4
+ version: 2.3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - RethinkDB Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-24 00:00:00.000000000 Z
11
+ date: 2016-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json