webmoney 0.0.14 → 0.0.15.pre

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.
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