otp 0.0.10 → 0.0.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81f98da9bacd6750a761f89590463ed0777b2b1d
4
- data.tar.gz: 710bb562bde9f46efcdf89f5e9777839ba8dbf37
3
+ metadata.gz: f29c79a8ef901714a1cbc348dfbd36c1f47e4e8e
4
+ data.tar.gz: 6e51d1a7b778f71092637fa5e3b698fc32f892a7
5
5
  SHA512:
6
- metadata.gz: a5921f7970174fafc13b4ce15de85f94772ae958338bab7645d9a5804e61b45a6e8ef1666e0a18075dfabb47e52d8356f6fe7a03575d6ac472b5471052a7c755
7
- data.tar.gz: 85f05deafa16e5232185255572003d7c3c477ada47079dcd393262983694030f24cc7e540e54d503c4f19f132aee103b1cb5c3b277301efd771cb42f56adbd2c
6
+ metadata.gz: e83401db9e5f49f49f86667091054f27834d273b505bb5918fe8c2c485292d692c420bd2096eed767093c754cf4c978429d233253937555830944211e727ed3b
7
+ data.tar.gz: 9e0fdec72d1b9701a53d3253b38479060ea6c04af63efc0bd33e0f1b38df5b753a002f74b8245f804305842158c2476c467a72e896491f545d586fc983114ab1
data/Rakefile CHANGED
@@ -6,4 +6,9 @@ Rake::TestTask.new(:test) do |test|
6
6
  test.verbose = true
7
7
  end
8
8
 
9
- task :default => :test
9
+ desc "Run rubocop"
10
+ task :rubocop do
11
+ sh "rubocop lib -f html -o rubocop.html"
12
+ end
13
+
14
+ task :default => [:test, :rubocop]
@@ -42,7 +42,7 @@ module OTP
42
42
  raise ArgumentError, "last must be greater than or equal to 0" if last < 0
43
43
  raise ArgumentError, "post must be greater than or equal to 0" if post < 0
44
44
  return false if given_pw.nil? || given_pw.empty?
45
- return (-last..post).any?{|i| compare(password(i), given_pw) }
45
+ return (-last..post).any?{|i| otp_compare(password(i), given_pw) }
46
46
  end
47
47
 
48
48
  def to_uri
@@ -10,68 +10,49 @@ module OTP
10
10
  "I"=>8, "J"=>9, "K"=>10, "L"=>11, "M"=>12, "N"=>13, "O"=>14, "P"=>15,
11
11
  "Q"=>16, "R"=>17, "S"=>18, "T"=>19, "U"=>20, "V"=>21, "W"=>22, "X"=>23,
12
12
  "Y"=>24, "Z"=>25, "2"=>26, "3"=>27, "4"=>28, "5"=>29, "6"=>30, "7"=>31,
13
- "="=>-1,
14
- }
15
-
16
- DECODE_LENGTH = {
17
- 1 => 1, # 5 bits -> 1 byte (irregular)
18
- 2 => 1, # 10 bits -> 1 byte
19
- 3 => 2, # 15 bits -> 2 bytes (irregular)
20
- 4 => 2, # 20 bits -> 2 bytes
21
- 5 => 3, # 25 bits -> 3 bytes
22
- 6 => 4, # 30 bits -> 4 bytes (irregular)
23
- 7 => 4, # 35 bits -> 4 bytes
24
- 8 => 5, # 40 bits -> 5 bytes
13
+ "0"=>14, "1"=>11, "8"=>1, # mistyped chars
14
+ " "=>-2, "-"=>-2, "\n"=>-2, "\r"=>-2, "\t"=>-2, # separators
15
+ "="=>-1, # padding
25
16
  }
26
17
 
27
18
  module_function
28
19
 
29
- def encode(bytes, padding: true)
20
+ def encode(bytes)
30
21
  return nil unless bytes
31
- pad = padding ? "=" : ""
32
- ret = ""
33
22
  bytes = bytes.dup.force_encoding("binary")
34
- off = 0
35
- while off < bytes.length
36
- n = 0
37
- bits = bytes[off, 5]
38
- off += 5
39
- l = (bits.length * 8.0 / 5.0).ceil
40
- bits << "\0" while bits.length < 5
41
- bits.each_byte{|b| n = (n << 8) | b }
42
- (1..8).each do |i|
43
- ret << ((i > l) ? pad : ENCODE_CHARS[(n >> (8-i)*5) & 0x1f])
23
+ ret = ""
24
+ offset = buffer = buffered = 0
25
+ while offset < bytes.length
26
+ buffer = ((buffer << 8) | bytes[offset].ord)
27
+ buffered += 8
28
+ offset += 1
29
+ while buffered >= 5
30
+ ret << ENCODE_CHARS[buffer >> (buffered - 5)]
31
+ buffered -= 5
32
+ buffer &= (0xff >> (8 - buffered))
44
33
  end
45
34
  end
35
+ if buffered > 0
36
+ ret << ENCODE_CHARS[buffer << (5 - buffered)]
37
+ end
46
38
  return ret
47
39
  end
48
40
 
49
41
  def decode(chars)
50
42
  return nil unless chars
51
- ret = ""
43
+ ret = "".force_encoding("binary")
52
44
  chars = chars.upcase
53
- ret.force_encoding("binary")
54
- off = 0
55
- while off < chars.length
56
- n = l = 0
57
- bits = chars[off, 8]
58
- off += 8
59
- bits << "=" while bits.length < 8
60
- bits.each_char.with_index do |c, i|
61
- d = DECODE_MAP[c]
62
- if d.nil?
63
- raise ArgumentError, "invalid char: #{c}"
64
- elsif d < 0
65
- n <<= 5 * (8-i)
66
- off = chars.length
67
- break
68
- else
69
- n <<= 5
70
- n |= d
71
- l = DECODE_LENGTH[i+1]
72
- end
73
- end
74
- ret << (1..l).map{|i| (n >> 40 - i * 8) & 0xff }.pack("c*")
45
+ buffer = buffered = 0
46
+ chars.each_char do |c|
47
+ d = DECODE_MAP[c]
48
+ raise ArgumentError, "invalid char: #{c}" if d.nil?
49
+ next if d == -2
50
+ break if d == -1
51
+ buffer = (buffer << 5) | d
52
+ buffered += 5
53
+ next if buffered < 8
54
+ ret << ((buffer >> (buffered - 8)) & 0xff)
55
+ buffered -= 8
75
56
  end
76
57
  return ret
77
58
  end
@@ -5,35 +5,35 @@ module OTP
5
5
  private
6
6
 
7
7
  def otp(algorithm, secret, moving_factor, digits)
8
- message = pack_int64(moving_factor)
9
- digest = hmac(algorithm, secret, message)
10
- num = pickup(digest)
11
- return truncate(num, digits)
8
+ message = otp_pack_int64(moving_factor)
9
+ digest = otp_hmac(algorithm, secret, message)
10
+ num = otp_pickup(digest)
11
+ return otp_truncate(num, digits)
12
12
  end
13
13
 
14
- def pack_int64(i)
14
+ def otp_pack_int64(i)
15
15
  return [i >> 32 & 0xffffffff, i & 0xffffffff].pack("NN")
16
16
  end
17
17
 
18
- def hmac(algorithm, secret, text)
18
+ def otp_hmac(algorithm, secret, text)
19
19
  mac = OpenSSL::HMAC.new(secret, algorithm)
20
20
  mac << text
21
21
  return mac.digest
22
22
  end
23
23
 
24
- def pickup(digest)
24
+ def otp_pickup(digest)
25
25
  offset = digest[-1].ord & 0xf
26
26
  binary = digest[offset, 4]
27
27
  return binary.unpack("N")[0] & 0x7fffffff
28
28
  end
29
29
 
30
- def truncate(num, digits)
30
+ def otp_truncate(num, digits)
31
31
  pw = (num % (10 ** digits)).to_s
32
32
  pw.prepend("0") while pw.length < digits
33
33
  return pw
34
34
  end
35
35
 
36
- def compare(a, b)
36
+ def otp_compare(a, b)
37
37
  return a.to_i == b.to_i
38
38
  end
39
39
  end
@@ -1,3 +1,3 @@
1
1
  module OTP
2
- VERSION = "0.0.10"
2
+ VERSION = "0.0.11"
3
3
  end
@@ -24,8 +24,8 @@ class TestBase < Test::Unit::TestCase
24
24
  assert_equal("", otp.secret)
25
25
  assert_equal("", otp.raw_secret)
26
26
 
27
- otp.secret = "MZXW6YTBOI======"
28
- assert_equal("MZXW6YTBOI======", otp.secret)
27
+ otp.secret = "MZXW6YTBOI"
28
+ assert_equal("MZXW6YTBOI", otp.secret)
29
29
  assert_equal("foobar", otp.raw_secret)
30
30
 
31
31
  otp.secret = "MZXW6YTBOI"
@@ -45,10 +45,21 @@ class TestBase < Test::Unit::TestCase
45
45
  assert_equal("", otp.raw_secret)
46
46
 
47
47
  otp.raw_secret = "foobarbaz"
48
- assert_equal("MZXW6YTBOJRGC6Q=", otp.secret)
48
+ assert_equal("MZXW6YTBOJRGC6Q", otp.secret)
49
49
  assert_equal("foobarbaz", otp.raw_secret)
50
50
  end
51
51
 
52
+ def test_verify
53
+ otp = OTP::Base.new
54
+ e = assert_raise(ArgumentError){ otp.verify("0", last:-1) }
55
+ assert_match(/last must be greater than or equal to 0/, e.message)
56
+ e = assert_raise(ArgumentError){ otp.verify("0", post:-1) }
57
+ assert_match(/post must be greater than or equal to 0/, e.message)
58
+ assert_equal(false, otp.verify(nil))
59
+ assert_equal(false, otp.verify(""))
60
+ assert_raise(NotImplementedError){ otp.verify("0") }
61
+ end
62
+
52
63
  def test_moving_factor
53
64
  base = OTP::Base.new
54
65
  hotp = OTP::HOTP.new
@@ -1,8 +1,8 @@
1
1
  require_relative "helper"
2
2
 
3
3
  class TestBase32 < Test::Unit::TestCase
4
- def assert_encode(encoded, plain, padding: true)
5
- assert_equal(encoded, ::OTP::Base32.encode(plain, padding: padding))
4
+ def assert_encode(encoded, plain)
5
+ assert_equal(encoded, ::OTP::Base32.encode(plain))
6
6
  end
7
7
 
8
8
  def assert_decode(plain, encoded)
@@ -10,58 +10,50 @@ class TestBase32 < Test::Unit::TestCase
10
10
  assert_equal(plain, ::OTP::Base32.decode(encoded))
11
11
  end
12
12
 
13
- def assert_encode_decode(plain, encoded, padding: true)
13
+ def assert_encode_decode(plain, encoded)
14
14
  assert_decode(plain, encoded)
15
- assert_encode(encoded, plain, padding: padding)
15
+ assert_encode(encoded, plain)
16
16
  end
17
17
 
18
18
  def test_base32
19
19
  assert_encode_decode(nil, nil)
20
20
  assert_encode_decode("", "")
21
- assert_encode_decode("f", "MY======")
22
- assert_encode_decode("fo", "MZXQ====")
23
- assert_encode_decode("foo", "MZXW6===")
24
- assert_encode_decode("foob", "MZXW6YQ=")
21
+ assert_encode_decode("f", "MY")
22
+ assert_encode_decode("fo", "MZXQ")
23
+ assert_encode_decode("foo", "MZXW6")
24
+ assert_encode_decode("foob", "MZXW6YQ")
25
25
  assert_encode_decode("fooba", "MZXW6YTB")
26
- assert_encode_decode("foobar", "MZXW6YTBOI======")
26
+ assert_encode_decode("foobar", "MZXW6YTBOI")
27
27
  assert_encode_decode("\u{3042}\u{3044}\u{3046}\u{3048}\u{304a}", "4OAYFY4BQTRYDBXDQGEOHAMK")
28
28
  end
29
29
 
30
- def test_base32_without_padding
31
- assert_encode_decode(nil, nil, padding: false)
32
- assert_encode_decode("", "", padding: false)
33
- assert_encode_decode("f", "MY", padding: false)
34
- assert_encode_decode("fo", "MZXQ", padding: false)
35
- assert_encode_decode("foo", "MZXW6", padding: false)
36
- assert_encode_decode("foob", "MZXW6YQ", padding: false)
37
- assert_encode_decode("fooba", "MZXW6YTB", padding: false)
38
- assert_encode_decode("foobar", "MZXW6YTBOI", padding: false)
39
- assert_encode_decode("\u{3042}\u{3044}\u{3046}\u{3048}\u{304a}", "4OAYFY4BQTRYDBXDQGEOHAMK", padding: false)
30
+ def test_decode_with_mistyped
31
+ assert_decode(OTP::Base32.decode("AOLB"), "A018")
32
+ assert_decode(OTP::Base32.decode("aolb"), "A018")
40
33
  end
41
34
 
42
- def test_truncated_decode
43
- assert_decode("f", "MY")
44
- assert_decode("fo", "MZXQ")
45
- assert_decode("foo", "MZXW6")
46
- assert_decode("foob", "MZXW6YQ")
47
- assert_decode("f", "my")
48
- assert_decode("fo", "mzxq")
49
- assert_decode("foo", "mzxw6")
50
- assert_decode("foob", "mzxw6yq")
35
+ def test_decode_include_space
36
+ assert_decode("f", "M Y")
37
+ assert_decode("fo", "MZ XQ")
38
+ assert_decode("foo", "M\nZ\rX\tW-6")
39
+ assert_decode("f", "m y")
40
+ assert_decode("fo", "mz xq")
41
+ assert_decode("foo", "m\nz\rx\tw-6")
51
42
  end
52
43
 
53
44
  def test_unspecified
54
- assert_raise(ArgumentError){ OTP::Base32.decode("MY0") }
45
+ e = assert_raise(ArgumentError){ OTP::Base32.decode("MY9") }
46
+ assert_equal("invalid char: 9", e.message)
55
47
  assert_decode("", "=")
56
- assert_decode("`", "M=======")
57
- assert_decode("fn", "MZX=====")
58
- assert_decode("foo`", "MZXW6Y==")
59
- assert_decode("`", "M=======G")
60
- assert_decode("fn", "MZX=====G")
61
- assert_decode("foo`", "MZXW6Y==G")
62
- assert_decode("`", "M")
63
- assert_decode("fn", "MZX")
64
- assert_decode("foo`", "MZXW6Y")
48
+ assert_decode("", "M=======")
49
+ assert_decode("f", "MZX=====")
50
+ assert_decode("foo", "MZXW6Y==")
51
+ assert_decode("", "M=======G")
52
+ assert_decode("f", "MZX=====G")
53
+ assert_decode("foo", "MZXW6Y==G")
54
+ assert_decode("", "M")
55
+ assert_decode("f", "MZX")
56
+ assert_decode("foo", "MZXW6Y")
65
57
  assert_decode("fooba", "MZXW6YTB===")
66
58
  assert_decode("f", "MY=AAAAA")
67
59
  assert_decode("fo", "MZXQ=AAA")
@@ -17,6 +17,11 @@ class TestURI < Test::Unit::TestCase
17
17
  assert_equal("account@example.com", otp.accountname)
18
18
  assert_equal("My Company", otp.issuer)
19
19
 
20
+ uri = "otpauth://totp/My%20Company%3A%20%20account@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
21
+ otp = OTP::URI.parse(uri)
22
+ assert_equal("account@example.com", otp.accountname)
23
+ assert_equal("My Company", otp.issuer)
24
+
20
25
  uri = "otpauth://totp/My%20Company:%20%20account@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Foo"
21
26
  otp = OTP::URI.parse(uri)
22
27
  assert_equal("account@example.com", otp.accountname)
@@ -113,6 +118,16 @@ class TestURI < Test::Unit::TestCase
113
118
  assert_equal(otp.password, hotp.password)
114
119
  end
115
120
 
121
+ def test_format_invalid
122
+ totp = OTP::TOTP.new
123
+ e = assert_raise(RuntimeError){ totp.to_uri }
124
+ assert_match(/secret must be set/, e.message)
125
+
126
+ totp.new_secret
127
+ e = assert_raise(RuntimeError){ totp.to_uri }
128
+ assert_match(/accountname must be set/, e.message)
129
+ end
130
+
116
131
  def test_parse_invalid
117
132
  e = assert_raise(RuntimeError){ OTP::URI.parse("http://www.netlab.jp") }
118
133
  assert_match(/URI scheme not match/, e.message)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuuzou Gotou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-09 00:00:00.000000000 Z
11
+ date: 2015-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler