ruby-mysql 2.9.14 → 3.0.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
- SHA1:
3
- metadata.gz: 113de8c9b46c75bf18b833a65205517938daf47d
4
- data.tar.gz: 675d64d8cc1185e7f394c4f201aa18f427b18f11
2
+ SHA256:
3
+ metadata.gz: f95fb29b93c207b23bbc1378ce78b10ab297269f0cf24409116a69502cdf9ae8
4
+ data.tar.gz: 7979ccfd21194e81a4c98f90920b7dc3cdb1165201bdf7bc0d640d16fbe8ebea
5
5
  SHA512:
6
- metadata.gz: 47b396bc40fa36e588d01899569f8b0cca6b256bb2d290fe2ce5ab44dc66a566c2b47d67f64cb8f4d2a8a0a62c352e878da681f88b89bc0a6811b12205754214
7
- data.tar.gz: 2aa55a288ce9c5ca4f22be8b8a2c6750be23592a0e030b0077f622b43195691f81de20831a359098ce8a270050e3ffa4ab794439b039c267d803f0d23ad2330e
6
+ metadata.gz: '068b6f6008f4b77dc6d34b660c8f06b73db2c06e63fc98d69d5455ceb6ab61c3924d158de4398d6b897cc2fa44d460a879b60355dbb16ac90f0af666f750467d'
7
+ data.tar.gz: 769105fbd5f16a4b8ab9c55c4a1243c962db3a238f05baa16d970cb2cbaadba0f0487c2daf194b53ce0bfa48639aac37cb79527da02518607a4a0a861cdd6caf
data/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ ## [3.0.0] - 2021-11-16
2
+
3
+ - `Mysql.new` no longer connect. use `Mysql.connect` or `Mysql#connect`.
4
+
5
+ - `Mysql.init` is removed. use `Mysql.new` instead.
6
+
7
+ - `Mysql.new`, `Mysql.conncet` and `Mysql#connect` takes URI object or URI string or Hash object.
8
+ example:
9
+ Mysql.connect('mysql://user:password@hostname:port/dbname?charset=ascii')
10
+ Mysql.connect('mysql://user:password@%2Ftmp%2Fmysql.sock/dbname?charset=ascii') # for UNIX socket
11
+ Mysql.connect('hostname', 'user', 'password', 'dbname')
12
+ Mysql.connect(host: 'hostname', username: 'user', password: 'password', database: 'dbname')
13
+
14
+ - `Mysql.options` is removed. use `Mysql#param = value` instead.
15
+ For example:
16
+ m = Mysql.init
17
+ m.options(Mysql::OPT_LOCAL_INFILE, true)
18
+ m.connect(host, user, passwd)
19
+ change to
20
+ m = Mysql.new
21
+ m.local_infile = true
22
+ m.connect(host, user, passwd)
23
+ or
24
+ m = Mysql.connect(host, user, passwd, local_infile: true)
25
+
26
+ - `Mysql::Time` is removed.
27
+ Instead, `Time` object is returned for the DATE, DATETIME, TIMESTAMP data,
28
+ and `Integer` object is returned for the TIME data.
29
+ If DATE, DATETIME, TIMESTAMP are invalid values for Time, nil is returned.
30
+
31
+ - meaningless methods are removed:
32
+ * `bind_result`
33
+ * `client_info`
34
+ * `client_version`
35
+ * `get_proto_info`
36
+ * `get_server_info`
37
+ * `get_server_version`
38
+ * `proto_info`
39
+ * `query_with_result`
40
+
41
+ - alias method are removed:
42
+ * `get_host_info`: use `host_info`
43
+ * `real_connect`: use `connect`
44
+ * `real_query`: use `query`
45
+
46
+ - methods corresponding to deprecated APIs in MySQL are removed:
47
+ * `list_dbs`: use `SHOW DATABASES`
48
+ * `list_fields`: use `SHOW COLUMNS`
49
+ * `list_processes`: use `SHOW PROCESSLIST`
50
+ * `list_tables`: use `SHOW TABLES`
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # ruby-mysql
2
+
3
+ ## Description
4
+
5
+ MySQL connector for Ruby.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ gem install ruby-mysql
11
+ ```
12
+
13
+ ## Synopsis
14
+
15
+ ```ruby
16
+ my = Mysql.connect('mysql://username:password@hostname:port/dbname?charset=utf8mb4')
17
+ my.query("select col1, col2 from tblname").each do |col1, col2|
18
+ p col1, col2
19
+ end
20
+ stmt = my.prepare('insert into tblname (col1,col2) values (?,?)')
21
+ stmt.execute 123, 'abc'
22
+ ```
23
+
24
+ ## Copyright
25
+
26
+ * Author: TOMITA Masahiro <tommy@tmtm.org>
27
+ * Copyright: Copyright 2008 TOMITA Masahiro
28
+ * License: MIT
@@ -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