webmoney 0.0.14 → 0.0.15.pre

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,5 +1,20 @@
1
1
  ChangeLog
2
2
 
3
+ Thu Nov 22 13:07:47 2012 +0400
4
+ ----------------------------
5
+ V 0.0.15.pre
6
+ * Changes in x509 cert/key configuration (backward compatible)
7
+ * Pure ruby implementation of signing algorithm (100 times faster),
8
+ thanks to Sergey Gridasov <grindars@gmail.com>
9
+
10
+ Thu Oct 25 13:47:06 2012 +0400
11
+ ----------------------------
12
+ V 0.0.14
13
+ * Added X9 interface (:balance)
14
+ * Added x509 version X11 interface (:get_passport)
15
+ * Some bugs fixed
16
+ * Fix compile Warning
17
+
3
18
  Wed Apr 11 2012 14:16:00 +0400
4
19
  ----------------------------
5
20
  V 0.0.13
data/README.md CHANGED
@@ -72,8 +72,20 @@ wmid = '111222333444'
72
72
 
73
73
  ## Light
74
74
 
75
+ The key convert instruction from P12 format to PEM see [here](http://wiki.webmoney.ru/projects/webmoney/wiki/konvertatsiya_klyuchey_wm_keeper_light_v_pem_format)
76
+
77
+ ```ruby
78
+ mywm = MyWM.new(:wmid => '123456789012',
79
+ :cert => 'webmoney.pem', # ~/.wm/webmoney.pem
80
+ # :cert => '/home/user/webmoney.pem',
81
+ :key => 'webmoney.key', # ~/.wm/webmoney.key
82
+ # :key => '/home/user/webmoney.key',
83
+ :password => 'pa$$w0rt')
84
+ ```
85
+ or
86
+
75
87
  ```ruby
76
- cert = OpenSSL::X509::Certificate.new(File.read("webmoney.cert"))
88
+ cert = OpenSSL::X509::Certificate.new(File.read("webmoney.pem"))
77
89
  key = OpenSSL::PKey::RSA.new(File.read("webmoney.key"), "password")
78
90
  mywm = MyWM.new(:wmid => '123456789012', :cert => cert, :key => key)
79
91
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.14
1
+ 0.0.15.pre
@@ -0,0 +1,128 @@
1
+ require "base64"
2
+ require "stringio"
3
+ require "openssl"
4
+ require "securerandom"
5
+
6
+ class Signer
7
+ module Key
8
+
9
+ def self.read(io, wmid, password = nil)
10
+ if !password.nil?
11
+
12
+ header = io.read 30
13
+ data = io.read
14
+
15
+ begin
16
+ return try_read_encrypted wmid, password, header, data
17
+ rescue
18
+ return try_read_encrypted wmid, password[0...password.length / 2], header, data
19
+ end
20
+ end
21
+
22
+ reserved1, sign_flag = io.read(4).unpack("vv")
23
+ crc = io.read(16)
24
+ length, = io.read(4).unpack("V")
25
+
26
+ data = io.read
27
+ raise "unexpected data length" if length != data.length
28
+
29
+ digest = OpenSSL::Digest::MD4.new
30
+ digest.update [ reserved1, 0 ].pack("v*")
31
+ digest.update [ 0, 0, 0, 0, length ].pack("V*")
32
+ digest.update data
33
+
34
+ calculated_crc = digest.digest
35
+
36
+ raise "invalid key digest" if crc != calculated_crc
37
+
38
+ data_io = StringIO.new data[4..-1], 'rb'
39
+
40
+ e = read_bn_from data_io
41
+ n = read_bn_from data_io
42
+
43
+ { e: e, n: n }
44
+ end
45
+
46
+ def self.try_read_encrypted(wmid, password, header, data)
47
+ nested_io = StringIO.new ''.encode('BINARY'), 'rb+'
48
+ nested_io.write header
49
+ nested_io.write wm_encrypt(wmid, password, data)
50
+ nested_io.rewind
51
+
52
+ return self.read nested_io, wmid
53
+ end
54
+
55
+ def self.read_bn_from(io)
56
+ bytes, = io.read(2).unpack("v")
57
+
58
+ data = io.read(bytes).reverse
59
+
60
+ OpenSSL::BN.new(data, 2)
61
+ end
62
+
63
+ def self.wm_encrypt(wmid, password, data)
64
+ data = data.dup
65
+
66
+ digest = OpenSSL::Digest::MD4.new
67
+ digest.update wmid
68
+ digest.update password
69
+
70
+ key = digest.digest.unpack("C*")
71
+ i = 0
72
+ while i < data.length
73
+ data[i] = (data[i].ord ^ key[i % key.length]).chr
74
+
75
+ i += 1
76
+ end
77
+
78
+ data
79
+ end
80
+ end
81
+
82
+ def initialize(wmid, password, key)
83
+ raise ArgumentError, "nil wmid" if wmid.nil?
84
+ raise ArgumentError, "Incorrect WMID" unless is_wmid wmid
85
+ raise ArgumentError, "nil password" if password.nil?
86
+ raise ArgumentError, "nil key" if key.nil?
87
+ raise ArgumentError, "Illegal size for base64 keydata" unless key.length == 220
88
+
89
+ key = Base64.decode64 key
90
+
91
+ raise ArgumentError, "Illegal size for keydata" if key.length != 164
92
+
93
+ io = StringIO.open key.force_encoding('BINARY'), 'rb'
94
+ @key = Key.read io, wmid, password
95
+ end
96
+
97
+ def sign(data)
98
+ raise ArgumentError, "nil data" if data.nil?
99
+
100
+ digest = OpenSSL::Digest::MD4.new
101
+ digest.update data
102
+ data = digest.digest.unpack("V*")
103
+
104
+ 10.times do
105
+ data << SecureRandom.random_number(1 << 32)
106
+ end
107
+
108
+ data = data.pack("V*")
109
+
110
+ data = ([ data.length ].pack("v") + data).ljust( @key[:n].num_bytes, 0.chr).reverse
111
+
112
+ data_bignum = OpenSSL::BN.new data, 2
113
+
114
+ signature = data_bignum.mod_exp(@key[:e], @key[:n])
115
+
116
+ signature.to_s(2).rjust(@key[:n].num_bytes, 0.chr).unpack('n*').reverse.map { |w| sprintf '%04x', w }.join
117
+ end
118
+
119
+ protected
120
+
121
+ def is_wmid(string)
122
+ if string =~ /^[0-9]{12}$/
123
+ true
124
+ else
125
+ false
126
+ end
127
+ end
128
+ end
@@ -10,7 +10,7 @@ require 'rubygems'
10
10
  require 'nokogiri'
11
11
 
12
12
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
13
- %w(wmsigner interfaces wmid passport purse request_xml request_retval request_result messenger).each{|lib| require lib}
13
+ %w(signer interfaces wmid passport purse request_xml request_retval request_result messenger).each{|lib| require lib}
14
14
 
15
15
  # Module for Webmoney lib. Instance contain info
16
16
  # for WMT-interfaces requests (wmid, key, etc).
@@ -29,7 +29,7 @@ module Webmoney
29
29
  class IncorrectPurseError < WebmoneyError; end
30
30
  class NonExistentWmidError < WebmoneyError; end
31
31
  class CaCertificateError < WebmoneyError; end
32
-
32
+
33
33
  attr_reader :wmid, :error, :errormsg, :last_request, :last_response, :interfaces, :rid
34
34
  attr_accessor :messenger
35
35
 
@@ -61,14 +61,24 @@ module Webmoney
61
61
 
62
62
  @wmid = Wmid.new(opt[:wmid])
63
63
 
64
- # classic or light
65
- case opt[:key]
66
- when String
67
- @signer = Signer.new(@wmid, opt[:password], opt[:key])
68
- when OpenSSL::PKey::RSA, OpenSSL::PKey::DSA
69
- @key = opt[:key]
70
- @cert = opt[:cert]
71
- #@password = opt[:password]
64
+ # When x509, key and cert is path to file or filename in ~/.wm/,
65
+ # or initialized PKey::RSA and X509::Certificate objects
66
+ def detect_file(option)
67
+ pathes = %w(%s ~/.wm/%s)
68
+ pathes.map{|path| File.expand_path(path % option)}.detect{|path| File.file?(path)}
69
+ end
70
+
71
+ if file = detect_file(opt[:key])
72
+ # light
73
+ @key = OpenSSL::PKey::RSA.new(File.read(file), opt[:password])
74
+ @cert = OpenSSL::X509::Certificate.new(File.read(detect_file(opt[:cert])))
75
+ elsif opt[:key].is_a? OpenSSL::PKey::RSA
76
+ # initialized OpenSSL::PKey::RSA objects
77
+ @key = opt[:key]
78
+ @cert = opt[:cert]
79
+ elsif opt[:password]
80
+ # key is classic base64-encoded key
81
+ @signer = Signer.new(@wmid, opt[:password], opt[:key])
72
82
  end
73
83
 
74
84
  # ca_cert or default
@@ -240,6 +250,8 @@ module Webmoney
240
250
 
241
251
  def check_libxml_version
242
252
  libxml = Nokogiri::VERSION_INFO['libxml']
253
+ return true if libxml.nil?
254
+
243
255
  [libxml['compiled'], libxml['loaded']].each do |ver|
244
256
  major, minor = ver.match(/^(\d+)\.(\d+).*/).to_a[1,2].map{|i| i.to_i}
245
257
  return false if major < 2 or minor < 7
data/rakefile CHANGED
@@ -3,9 +3,7 @@ require 'rake'
3
3
  require 'rake/clean'
4
4
  require 'rake/extensiontask'
5
5
 
6
- CLEAN.include ["ext/wmsigner/*.{so,o}", "ext/wmsigner/Makefile", "lib/wmsigner.so", "pkg", "tmp"]
7
-
8
- Rake::ExtensionTask.new('wmsigner')
6
+ CLEAN.include ["pkg"]
9
7
 
10
8
  require 'rspec/core'
11
9
  require 'rspec/core/rake_task'
@@ -30,13 +28,6 @@ spec = begin
30
28
  gemspec.summary = "Webmoney interfaces and native wmsigner"
31
29
  gemspec.files += %w( ChangeLog ) + Dir.glob( 'ssl-certs/*.crt' )
32
30
  gemspec.test_files += %w( Gemfile ) + Dir.glob( 'spec/**/*.rb' )
33
-
34
- if RUBY_PLATFORM.match("win32")
35
- gemspec.platform = Gem::Platform::WIN32
36
- gemspec.files += []
37
- else
38
- gemspec.platform = Gem::Platform::RUBY
39
- gemspec.extensions = Dir.glob( 'ext/**/extconf.rb' )
40
- end
31
+ gemspec.add_dependency "jruby-openssl" if RUBY_PLATFORM == "java"
41
32
  end
42
33
  end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'benchmark'
4
+ require "#{File.expand_path File.dirname(__FILE__)}/spec_helper"
5
+
6
+ @wm = TestWM.new
7
+ n = 100
8
+ puts Benchmark.measure {
9
+ n.times do
10
+ @wm.send(:sign, 'abc123')
11
+ end
12
+ }
@@ -32,33 +32,12 @@ class TestWM
32
32
  end
33
33
 
34
34
  def getwm(config)
35
- if config.wmtype == "light"
36
- # light
37
- cert = OpenSSL::X509::Certificate.new(
38
- begin
39
- File.read(config.cert)
40
- rescue
41
- File.read("#{ENV['HOME']}/.wm/#{config.cert}")
42
- end)
43
- key = OpenSSL::PKey::RSA.new(
44
- begin
45
- File.read(config.key)
46
- rescue
47
- File.read("#{ENV['HOME']}/.wm/#{config.key}")
48
- end, config.password)
49
- TestWM.new :wmid => config.wmid,
50
- :key => key,
51
- :cert => cert,
52
- :ca_cert => WmConfig.ca_cert,
53
- :rid => config.rid
54
- else
55
- # classic
56
- TestWM.new :wmid => config.wmid,
57
- :password => config.password,
58
- :key => config.key,
59
- :ca_cert => config.ca_cert,
60
- :rid => config.rid
61
- end
35
+ TestWM.new :wmid => config.wmid,
36
+ :key => config.key,
37
+ :password => config.password,
38
+ :cert => config.cert,
39
+ :ca_cert => WmConfig.ca_cert,
40
+ :rid => config.rid
62
41
  end
63
42
 
64
43
  def webmoney
@@ -3,8 +3,8 @@ require 'spec_helper'
3
3
 
4
4
  describe "interfaces url" do
5
5
 
6
- let(:wmc) { TestWM.new } # classic
7
- let(:wml) { TestWM.new :wmid => WmConfig.first['wmid'], :key => nil } # light
6
+ let(:wmc) { webmoney } # classic
7
+ let(:wml) { contragent } # light
8
8
 
9
9
  it "should be exactly type" do
10
10
  wmc.should be_classic # @wm.classic? == true
@@ -5,13 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "webmoney"
8
- s.version = "0.0.14"
8
+ s.version = "0.0.15.pre"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Alexander Oryol"]
12
- s.date = "2012-10-25"
12
+ s.date = "2012-11-22"
13
13
  s.email = "eagle.alex@gmail.com"
14
- s.extensions = ["ext/wmsigner/extconf.rb"]
15
14
  s.extra_rdoc_files = [
16
15
  "ChangeLog",
17
16
  "README.md"
@@ -22,22 +21,6 @@ Gem::Specification.new do |s|
22
21
  "README.md",
23
22
  "RUNNING_TESTS",
24
23
  "VERSION",
25
- "ext/wmsigner/base64.cpp",
26
- "ext/wmsigner/base64.h",
27
- "ext/wmsigner/cmdbase.cpp",
28
- "ext/wmsigner/cmdbase.h",
29
- "ext/wmsigner/crypto.cpp",
30
- "ext/wmsigner/crypto.h",
31
- "ext/wmsigner/extconf.rb",
32
- "ext/wmsigner/md4.cpp",
33
- "ext/wmsigner/md4.h",
34
- "ext/wmsigner/rsalib1.cpp",
35
- "ext/wmsigner/rsalib1.h",
36
- "ext/wmsigner/signer.cpp",
37
- "ext/wmsigner/signer.h",
38
- "ext/wmsigner/stdafx.cpp",
39
- "ext/wmsigner/stdafx.h",
40
- "ext/wmsigner/wmsigner.cpp",
41
24
  "lib/interfaces.rb",
42
25
  "lib/messenger.rb",
43
26
  "lib/passport.rb",
@@ -45,9 +28,11 @@ Gem::Specification.new do |s|
45
28
  "lib/request_result.rb",
46
29
  "lib/request_retval.rb",
47
30
  "lib/request_xml.rb",
31
+ "lib/signer.rb",
48
32
  "lib/webmoney.rb",
49
33
  "lib/wmid.rb",
50
34
  "rakefile",
35
+ "spec/benchmark.rb",
51
36
  "spec/spec_helper.rb",
52
37
  "spec/unit/balance_spec.rb",
53
38
  "spec/unit/check_user.rb",
@@ -71,7 +56,7 @@ Gem::Specification.new do |s|
71
56
  s.rubyforge_project = "webmoney"
72
57
  s.rubygems_version = "1.8.24"
73
58
  s.summary = "Webmoney interfaces and native wmsigner"
74
- s.test_files = ["Gemfile", "spec/spec_helper.rb", "spec/unit/balance_spec.rb", "spec/unit/purse_spec.rb", "spec/unit/time_spec.rb", "spec/unit/check_user.rb", "spec/unit/interfaces_spec.rb", "spec/unit/messenger_spec.rb", "spec/unit/signer_spec.rb", "spec/unit/passport_spec.rb", "spec/unit/trust_spec.rb", "spec/unit/wmid_spec.rb", "spec/unit/login_spec.rb", "spec/unit/webmoney_spec.rb", "spec/unit/iconv_spec.rb"]
59
+ s.test_files = ["Gemfile", "spec/spec_helper.rb", "spec/benchmark.rb", "spec/unit/balance_spec.rb", "spec/unit/purse_spec.rb", "spec/unit/time_spec.rb", "spec/unit/check_user.rb", "spec/unit/interfaces_spec.rb", "spec/unit/messenger_spec.rb", "spec/unit/signer_spec.rb", "spec/unit/passport_spec.rb", "spec/unit/trust_spec.rb", "spec/unit/wmid_spec.rb", "spec/unit/login_spec.rb", "spec/unit/webmoney_spec.rb", "spec/unit/iconv_spec.rb"]
75
60
 
76
61
  if s.respond_to? :specification_version then
77
62
  s.specification_version = 3
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webmoney
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
5
- prerelease:
4
+ version: 0.0.15.pre
5
+ prerelease: 7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alexander Oryol
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-25 00:00:00.000000000 Z
12
+ date: 2012-11-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -94,8 +94,7 @@ dependencies:
94
94
  description:
95
95
  email: eagle.alex@gmail.com
96
96
  executables: []
97
- extensions:
98
- - ext/wmsigner/extconf.rb
97
+ extensions: []
99
98
  extra_rdoc_files:
100
99
  - ChangeLog
101
100
  - README.md
@@ -105,22 +104,6 @@ files:
105
104
  - README.md
106
105
  - RUNNING_TESTS
107
106
  - VERSION
108
- - ext/wmsigner/base64.cpp
109
- - ext/wmsigner/base64.h
110
- - ext/wmsigner/cmdbase.cpp
111
- - ext/wmsigner/cmdbase.h
112
- - ext/wmsigner/crypto.cpp
113
- - ext/wmsigner/crypto.h
114
- - ext/wmsigner/extconf.rb
115
- - ext/wmsigner/md4.cpp
116
- - ext/wmsigner/md4.h
117
- - ext/wmsigner/rsalib1.cpp
118
- - ext/wmsigner/rsalib1.h
119
- - ext/wmsigner/signer.cpp
120
- - ext/wmsigner/signer.h
121
- - ext/wmsigner/stdafx.cpp
122
- - ext/wmsigner/stdafx.h
123
- - ext/wmsigner/wmsigner.cpp
124
107
  - lib/interfaces.rb
125
108
  - lib/messenger.rb
126
109
  - lib/passport.rb
@@ -128,9 +111,11 @@ files:
128
111
  - lib/request_result.rb
129
112
  - lib/request_retval.rb
130
113
  - lib/request_xml.rb
114
+ - lib/signer.rb
131
115
  - lib/webmoney.rb
132
116
  - lib/wmid.rb
133
117
  - rakefile
118
+ - spec/benchmark.rb
134
119
  - spec/spec_helper.rb
135
120
  - spec/unit/balance_spec.rb
136
121
  - spec/unit/check_user.rb
@@ -163,13 +148,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
148
  version: '0'
164
149
  segments:
165
150
  - 0
166
- hash: 1774018962906030977
151
+ hash: 3598956069163173329
167
152
  required_rubygems_version: !ruby/object:Gem::Requirement
168
153
  none: false
169
154
  requirements:
170
- - - ! '>='
155
+ - - ! '>'
171
156
  - !ruby/object:Gem::Version
172
- version: '0'
157
+ version: 1.3.1
173
158
  requirements: []
174
159
  rubyforge_project: webmoney
175
160
  rubygems_version: 1.8.24
@@ -179,6 +164,7 @@ summary: Webmoney interfaces and native wmsigner
179
164
  test_files:
180
165
  - Gemfile
181
166
  - spec/spec_helper.rb
167
+ - spec/benchmark.rb
182
168
  - spec/unit/balance_spec.rb
183
169
  - spec/unit/purse_spec.rb
184
170
  - spec/unit/time_spec.rb