rethinkdb 2.2.0.4 → 2.3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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