ruby-mysql 2.10.0 → 2.11.0

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: '03296aa0e624e599242e8efc5d3011b4337e161c3b7bf1c9cc81e98fa99f5052'
4
- data.tar.gz: c7391d48dab125e86b97b8130556e69ceadf503e11884744b7fdf19af3b58cf1
3
+ metadata.gz: 40bdb4e1eba4eca2ed1e93524260bd9407f91ee5f65b8c32b8c38524ef05ebdd
4
+ data.tar.gz: 224ad0bdf2050dca6e5d7a603bd64cb44a5f414270aa06b9dd89690cd2665a32
5
5
  SHA512:
6
- metadata.gz: ba1a7bad362dc1523de97aa487ee8c571649854a2bb8a9342ecd525dbda0441c9562639556dcd933f7e7c643373907144329e97c2600af30a5ae6b1cc5fb5606
7
- data.tar.gz: bdea4b3d97980fea097d59525b327c275374d006ddb699efda0c359608d8588a8beba742f713f0b2721433ea5efbf9eac5db8d7f4e6d7ddbe9eeb050220e6a3d
6
+ metadata.gz: a73e1ab248a44935cd4115c0d2de16f491d51b2eb7ab7a9b33185a0f478be8753cc226ea78d645a2bb1ae0b09cb15a7432f9e8d5a1dfa82af3ef016783689544
7
+ data.tar.gz: 37db0a8b13b5a543cf9d552801aa0419c4ccce9fbe287d8df0335002df728e5e5ab5a9d82c873c174dec547b1077730cd265a4a6ace1714c88cb984b3d5f4134
data/README.rdoc CHANGED
@@ -20,8 +20,6 @@ MySQL connector for Ruby.
20
20
 
21
21
  * MySQL/Ruby 2.8.x とほぼ互換があります。
22
22
 
23
- * MySQL 8.0 には対応していません。
24
-
25
23
  == Synopsis
26
24
 
27
25
  使用例:
@@ -35,17 +33,17 @@ MySQL connector for Ruby.
35
33
 
36
34
  == Incompatible with MySQL/Ruby 2.8.x
37
35
 
38
- * Ruby 1.8.x ではシフトJISのような安全でないマルチバイト文字セットに対して Mysql#escape_string を使用すると例外が発生します。
39
-
40
36
  * いくつかのメソッドがありません: Mysql#debug, Mysql#change_user,
41
37
  Mysql#create_db, Mysql#drop_db, Mysql#dump_debug_info,
42
38
  Mysql#ssl_set, Mysql#reconnect
43
39
 
44
40
  * Mysql#options でサポートしているオプションは次のものだけです:
45
41
  Mysql::INIT_COMMAND, Mysql::OPT_CONNECT_TIMEOUT,
42
+ Mysql::OPT_GET_SERVER_PUBLIC_KEY,
43
+ Mysql::OPT_LOAD_DATA_LOCAL_DIR,
46
44
  Mysql::OPT_LOCAL_INFILE, Mysql::OPT_READ_TIMEOUT,
47
- Mysql::OPT_WRITE_TIMEOUT, Mysql::SET_CHARSET_NAME,
48
- Mysql::OPT_LOAD_DATA_LOCAL_DIR.
45
+ Mysql::OPT_SSL_MODE,
46
+ Mysql::OPT_WRITE_TIMEOUT, Mysql::SET_CHARSET_NAME.
49
47
  これら以外を指定すると "option not implementted" という warning が標準エラー出力に出力されます。
50
48
 
51
49
  * Mysql#use_result は Mysql#store_result と同じです。つまりサーバーから一気に結果セットを読み込みます。
@@ -0,0 +1,62 @@
1
+ require 'digest/sha2'
2
+
3
+ class Mysql
4
+ class Authenticator
5
+ class CachingSha2Password
6
+ # @param protocol [Mysql::Protocol]
7
+ def initialize(protocol)
8
+ @protocol = protocol
9
+ end
10
+
11
+ # @return [String]
12
+ def name
13
+ 'caching_sha2_password'
14
+ end
15
+
16
+ # @param passwd [String]
17
+ # @param scramble [String]
18
+ # @yield [String] hashed password
19
+ # @return [Mysql::Packet]
20
+ def authenticate(passwd, scramble)
21
+ yield hash_password(passwd, scramble)
22
+ pkt = @protocol.read
23
+ data = pkt.to_s
24
+ if data.size == 2 && data[0] == "\x01"
25
+ case data[1]
26
+ when "\x03" # fast_auth_success
27
+ # OK
28
+ when "\x04" # perform_full_authentication
29
+ if @protocol.client_flags & CLIENT_SSL != 0
30
+ @protocol.write passwd+"\0"
31
+ elsif !@protocol.get_server_public_key
32
+ raise 'Authentication requires secure connection'
33
+ else
34
+ @protocol.write "\2" # request public key
35
+ pkt = @protocol.read
36
+ pkt.utiny # skip
37
+ pubkey = pkt.to_s
38
+ hash = (passwd+"\0").unpack("C*").zip(scramble.unpack("C*")).map{|a, b| a ^ b}.pack("C*")
39
+ enc = OpenSSL::PKey::RSA.new(pubkey).public_encrypt(hash, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
40
+ @protocol.write enc
41
+ end
42
+ else
43
+ raise "invalid auth reply packet: #{data.inspect}"
44
+ end
45
+ pkt = @protocol.read
46
+ end
47
+ return pkt
48
+ end
49
+
50
+ # @param passwd [String]
51
+ # @param scramble [String]
52
+ # @return [String] hashed password
53
+ def hash_password(passwd, scramble)
54
+ return '' if passwd.nil? or passwd.empty?
55
+ hash1 = Digest::SHA256.digest(passwd)
56
+ hash2 = Digest::SHA256.digest(hash1)
57
+ hash3 = Digest::SHA256.digest(hash2 + scramble)
58
+ hash1.unpack("C*").zip(hash3.unpack("C*")).map{|a, b| a ^ b}.pack("C*")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,37 @@
1
+ require 'digest/sha1'
2
+
3
+ class Mysql
4
+ class Authenticator
5
+ class MysqlNativePassword
6
+ # @param protocol [Mysql::Protocol]
7
+ def initialize(protocol)
8
+ @protocol = protocol
9
+ end
10
+
11
+ # @return [String]
12
+ def name
13
+ 'mysql_native_password'
14
+ end
15
+
16
+ # @param passwd [String]
17
+ # @param scramble [String]
18
+ # @yield [String] hashed password
19
+ # @return [Mysql::Packet]
20
+ def authenticate(passwd, scramble)
21
+ yield hash_password(passwd, scramble)
22
+ @protocol.read
23
+ end
24
+
25
+ # @param passwd [String]
26
+ # @param scramble [String]
27
+ # @return [String] hashed password
28
+ def hash_password(passwd, scramble)
29
+ return '' if passwd.nil? or passwd.empty?
30
+ hash1 = Digest::SHA1.digest(passwd)
31
+ hash2 = Digest::SHA1.digest(hash1)
32
+ hash3 = Digest::SHA1.digest(scramble + hash2)
33
+ hash1.unpack("C*").zip(hash3.unpack("C*")).map{|a, b| a ^ b}.pack("C*")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ require 'openssl'
2
+
3
+ class Mysql
4
+ class Authenticator
5
+ class Sha256Password
6
+ # @param protocol [Mysql::Protocol]
7
+ def initialize(protocol)
8
+ @protocol = protocol
9
+ end
10
+
11
+ # @return [String]
12
+ def name
13
+ 'sha256_password'
14
+ end
15
+
16
+ # @param passwd [String]
17
+ # @param scramble [String]
18
+ # @yield [String] hashed password
19
+ # @return [Mysql::Packet]
20
+ def authenticate(passwd, scramble)
21
+ if @protocol.client_flags & CLIENT_SSL != 0
22
+ yield passwd+"\0"
23
+ return @protocol.read
24
+ end
25
+ yield "\x01" # request public key
26
+ pkt = @protocol.read
27
+ data = pkt.to_s
28
+ if data[0] == "\x01"
29
+ pkt.utiny # skip
30
+ pubkey = pkt.to_s
31
+ hash = (passwd+"\0").unpack("C*").zip(scramble.unpack("C*")).map{|a, b| a ^ b}.pack("C*")
32
+ enc = OpenSSL::PKey::RSA.new(pubkey).public_encrypt(hash, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
33
+ @protocol.write enc
34
+ pkt = @protocol.read
35
+ end
36
+ return pkt
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,84 @@
1
+ class Mysql
2
+ class Authenticator
3
+ @plugins = {}
4
+
5
+ # @param plugin [String]
6
+ def self.plugin_class(plugin)
7
+ return @plugins[plugin] if @plugins[plugin]
8
+
9
+ raise ClientError, "invalid plugin name: #{plugin}" unless plugin.match?(/\A\w+\z/)
10
+ begin
11
+ require_relative "authenticator/#{plugin}"
12
+ rescue LoadError
13
+ return nil
14
+ end
15
+ class_name = plugin.gsub(/(?:^|_)(.)/){$1.upcase}
16
+ raise ClientError, "#{class_name} is undefined" unless self.const_defined? class_name
17
+ klass = self.const_get(class_name)
18
+ @plugins[plugin] = klass
19
+ return klass
20
+ end
21
+
22
+ def initialize(protocol)
23
+ @protocol = protocol
24
+ end
25
+
26
+ # @param plugin [String]
27
+ def get(plugin)
28
+ self.class.plugin_class(plugin)
29
+ end
30
+
31
+ # @param plugin [String]
32
+ def get!(plugin)
33
+ get(plugin) or raise ClientError, "unknown plugin: #{plugin}"
34
+ end
35
+
36
+ def authenticate(user, passwd, db, scramble, plugin_name)
37
+ plugin = (get(plugin_name) || DummyPlugin).new(@protocol)
38
+ pkt = plugin.authenticate(passwd, scramble) do |hashed|
39
+ @protocol.write Protocol::AuthenticationPacket.serialize(@protocol.client_flags, 1024**3, @protocol.charset.number, user, hashed, db, plugin.name)
40
+ end
41
+ while true
42
+ res = Protocol::AuthenticationResultPacket.parse(pkt)
43
+ case res.result
44
+ when 0 # OK
45
+ break
46
+ when 2 # multi factor auth
47
+ raise ClientError, 'multi factor authentication is not supported'
48
+ when 254 # change auth plugin
49
+ plugin = get!(res.auth_plugin).new(@protocol)
50
+ pkt = plugin.authenticate(passwd, res.scramble) do |hashed|
51
+ if passwd.nil? || passwd.empty?
52
+ @protocol.write "\0"
53
+ else
54
+ @protocol.write hashed
55
+ end
56
+ end
57
+ else
58
+ raise ClientError, "invalid packet: #{pkt.to_s}"
59
+ end
60
+ end
61
+ end
62
+
63
+ class DummyPlugin
64
+ # @param protocol [Mysql::Protocol]
65
+ def initialize(protocol)
66
+ @protocol = protocol
67
+ end
68
+
69
+ # @return [String]
70
+ def name
71
+ ''
72
+ end
73
+
74
+ # @param passwd [String]
75
+ # @param scramble [String]
76
+ # @yield [String] hashed password
77
+ # @return [Mysql::Packet]
78
+ def authenticate(passwd, scramble)
79
+ yield ''
80
+ @protocol.read
81
+ end
82
+ end
83
+ end
84
+ end