otp 0.0.10 → 0.0.11

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