yubikey 1.2.1 → 1.3.0
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/README.md +70 -0
- data/lib/yubikey.rb +4 -4
- data/lib/yubikey/otp.rb +24 -14
- data/lib/yubikey/otp_verify.rb +63 -11
- data/spec/hex_spec.rb +14 -15
- data/spec/spec_helper.rb +3 -8
- metadata +29 -56
- data/README.rdoc +0 -49
- data/spec/spec.opts +0 -1
- data/spec/yubikey_modhex_spec.rb +0 -31
- data/spec/yubikey_otp_spec.rb +0 -28
- data/spec/yubikey_otp_verify_spec.rb +0 -38
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# yubikey
|
2
|
+
|
3
|
+
[](https://travis-ci.org/rainforestapp/yubikey)
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
A library to verify, decode, decrypt and parse [Yubikey](http://www.yubico.com/home/index/) one-time passwords.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### OTP Decryption
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
key = 'ecde18dbe76fbd0c33330f1c354871db'
|
15
|
+
otp = 'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
|
16
|
+
token = Yubikey::OTP.new(otp, key)
|
17
|
+
|
18
|
+
p "Device public id: #{token.public_id}" #=> 'dteffuje'
|
19
|
+
p "Device secret id: #{token.secret_id}" #=> '8792ebfe26cc'
|
20
|
+
p "Device insertions: #{token.insert_counter}" #=> 19
|
21
|
+
p "Session activation counter: #{token.session_counter}" #=> 17
|
22
|
+
p "Session timestamp: #{token.timestamp}" #=> 49712
|
23
|
+
p "OTP random data: #{token.random_number}" #=> 40904
|
24
|
+
```
|
25
|
+
|
26
|
+
### OTP Verification
|
27
|
+
Use your own `api_key` and `api_id`, which you can get at [yubico.com](https://upgrade.yubico.com/getapikey/).
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
begin
|
31
|
+
otp = Yubikey::OTP::Verify.new(:api_id => 1234,
|
32
|
+
:api_key => 'NiSwGZBQ0gTbwXbRGWAf4kM5xXg=',
|
33
|
+
:otp => 'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh')
|
34
|
+
|
35
|
+
if otp.valid?
|
36
|
+
p 'valid OTP'
|
37
|
+
elsif otp.replayed?
|
38
|
+
p 'replayed OTP'
|
39
|
+
end
|
40
|
+
rescue Yubikey::OTP::InvalidOTPError
|
41
|
+
p 'invalid OTP'
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Install
|
46
|
+
|
47
|
+
Yubikey is available as a gem, to install it just install the gem:
|
48
|
+
|
49
|
+
gem install yubikey
|
50
|
+
|
51
|
+
If you're using Bundler, add the gem to Gemfile.
|
52
|
+
|
53
|
+
gem 'yubikey'
|
54
|
+
|
55
|
+
Then run bundle install.
|
56
|
+
|
57
|
+
## Copyright
|
58
|
+
|
59
|
+
### Ruby library
|
60
|
+
Written by [Jonathan Rudenberg](https://github.com/titanous) <jon335@gmail.com>
|
61
|
+
Copyright (c) 2009 Jonathan Rudenberg
|
62
|
+
The MIT License. See LICENSE.
|
63
|
+
|
64
|
+
### Contributors
|
65
|
+
- Carl Byström
|
66
|
+
- Erik Ruwalder
|
67
|
+
- [Russell Smith](https://github.com/ukd1)
|
68
|
+
- [Chris Lundquist](https://github.com/ChrisLundquist)
|
69
|
+
- [Maarten van Grootel](https://github.com/maartenvg)
|
70
|
+
- [Chris Benedict](https://github.com/chrisbdaemon)
|
data/lib/yubikey.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$LOAD_PATH.include?(File.dirname(__FILE__)) || $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
4
|
require 'net/https'
|
5
|
-
require '
|
5
|
+
require 'openssl'
|
6
6
|
|
7
7
|
module Yubikey; end;
|
8
8
|
|
9
9
|
require 'yubikey/hex'
|
10
10
|
require 'yubikey/modhex'
|
11
11
|
require 'yubikey/otp'
|
12
|
-
require 'yubikey/otp_verify'
|
12
|
+
require 'yubikey/otp_verify'
|
data/lib/yubikey/otp.rb
CHANGED
@@ -15,31 +15,41 @@ class Yubikey::OTP
|
|
15
15
|
attr_reader :session_counter
|
16
16
|
# random integer used as padding and extra random noise
|
17
17
|
attr_reader :random_number
|
18
|
-
|
19
|
-
|
18
|
+
|
19
|
+
|
20
20
|
# Decode/decrypt a Yubikey one-time password
|
21
21
|
#
|
22
22
|
# [+otp+] ModHex encoded Yubikey OTP (at least 32 characters)
|
23
23
|
# [+key+] 32-character hex AES key
|
24
|
-
def initialize(otp, key)
|
24
|
+
def initialize(otp, key)
|
25
|
+
|
26
|
+
# Get the public ID first
|
27
|
+
@public_id = otp[0, 12]
|
28
|
+
|
29
|
+
# Strip prefix so otp will decode (following from yubico-c library)
|
30
|
+
otp = otp[-32,32] if otp.length > 32
|
31
|
+
|
25
32
|
raise InvalidOTPError, 'OTP must be at least 32 characters of modhex' unless otp.modhex? && otp.length >= 32
|
26
33
|
raise InvalidKeyError, 'Key must be 32 hex characters' unless key.hex? && key.length == 32
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
|
35
|
+
|
30
36
|
@token = Yubikey::ModHex.decode(otp[-32,32])
|
31
37
|
@aes_key = key.to_bin
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
|
39
|
+
decrypter = OpenSSL::Cipher.new('AES-128-ECB').decrypt
|
40
|
+
decrypter.key = @aes_key
|
41
|
+
decrypter.padding = 0
|
42
|
+
|
43
|
+
@token = decrypter.update(@token) + decrypter.final
|
44
|
+
|
35
45
|
raise BadCRCError unless crc_valid?
|
36
|
-
|
46
|
+
|
37
47
|
@secret_id, @insert_counter, @timestamp, @timestamp_lo, @session_counter, @random_number, @crc = @token.unpack('H12vvCCvv')
|
38
48
|
@timestamp += @timestamp_lo * 65536
|
39
49
|
end
|
40
|
-
|
50
|
+
|
41
51
|
private
|
42
|
-
|
52
|
+
|
43
53
|
def crc_valid?
|
44
54
|
crc = 0xffff
|
45
55
|
@token.each_byte do |b|
|
@@ -52,9 +62,9 @@ class Yubikey::OTP
|
|
52
62
|
end
|
53
63
|
crc == 0xf0b8
|
54
64
|
end
|
55
|
-
|
65
|
+
|
56
66
|
# :stopdoc:
|
57
67
|
class InvalidOTPError < StandardError; end
|
58
68
|
class InvalidKeyError < StandardError; end
|
59
69
|
class BadCRCError < StandardError; end
|
60
|
-
end # Yubikey::OTP
|
70
|
+
end # Yubikey::OTP
|
data/lib/yubikey/otp_verify.rb
CHANGED
@@ -1,16 +1,26 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'securerandom'
|
3
|
+
|
1
4
|
module Yubikey
|
2
5
|
|
3
|
-
API_URL = 'https://api.yubico.com/wsapi/'
|
4
|
-
|
5
|
-
API_KEY = 'e928a7d3076516a8c8c879f42c3ea0388f3b19f'
|
6
|
-
|
6
|
+
API_URL = 'https://api.yubico.com/wsapi/2.0/'
|
7
|
+
|
7
8
|
class OTP::Verify
|
8
|
-
|
9
9
|
# The raw status from the Yubico server
|
10
10
|
attr_reader :status
|
11
|
-
|
12
|
-
def initialize(
|
13
|
-
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
raise(ArgumentError, "Must supply API ID") if args[:api_id].nil?
|
14
|
+
raise(ArgumentError, "Must supply API Key") if args[:api_key].nil?
|
15
|
+
raise(ArgumentError, "Must supply OTP") if args[:otp].nil?
|
16
|
+
|
17
|
+
@api_key = args[:api_key]
|
18
|
+
@api_id = args[:api_id]
|
19
|
+
|
20
|
+
@url = args[:url] || API_URL
|
21
|
+
@nonce = args[:nonce] || OTP::Verify.generate_nonce(32)
|
22
|
+
|
23
|
+
verify(args)
|
14
24
|
end
|
15
25
|
|
16
26
|
def valid?
|
@@ -23,8 +33,10 @@ module Yubikey
|
|
23
33
|
|
24
34
|
private
|
25
35
|
|
26
|
-
def verify(
|
27
|
-
|
36
|
+
def verify(args)
|
37
|
+
query = "id=#{@api_id}&otp=#{args[:otp]}&nonce=#{@nonce}"
|
38
|
+
|
39
|
+
uri = URI.parse(@url) + 'verify'
|
28
40
|
uri.query = query
|
29
41
|
|
30
42
|
http = Net::HTTP.new(uri.host, uri.port)
|
@@ -33,12 +45,52 @@ module Yubikey
|
|
33
45
|
|
34
46
|
req = Net::HTTP::Get.new(uri.request_uri)
|
35
47
|
result = http.request(req).body
|
36
|
-
|
48
|
+
|
37
49
|
@status = result[/status=(.*)$/,1].strip
|
38
50
|
|
39
51
|
if @status == 'BAD_OTP' || @status == 'BACKEND_ERROR'
|
40
52
|
raise OTP::InvalidOTPError, "Received error: #{@status}"
|
41
53
|
end
|
54
|
+
|
55
|
+
if ! verify_response(result)
|
56
|
+
@status = 'BAD_RESPONSE'
|
57
|
+
return
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def verify_response(result)
|
62
|
+
|
63
|
+
signature = result[/^h=(.+)$/, 1].strip
|
64
|
+
returned_nonce = result[/nonce=(.+)$/, 1]
|
65
|
+
returned_nonce.strip! unless returned_nonce.nil?
|
66
|
+
|
67
|
+
if @nonce != returned_nonce
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
generated_signature = OTP::Verify.generate_hmac(result, @api_key)
|
72
|
+
|
73
|
+
return signature == generated_signature
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def self.generate_nonce(length)
|
78
|
+
return SecureRandom.hex length/2
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def self.generate_hmac(response, api_key)
|
83
|
+
response_params = response.split(' ')
|
84
|
+
response_params.reject! do |p|
|
85
|
+
p =~ /^h=(.+)$/
|
86
|
+
end
|
87
|
+
|
88
|
+
response_string = response_params.sort.join('&')
|
89
|
+
response_string.strip!
|
90
|
+
|
91
|
+
hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(api_key), response_string)
|
92
|
+
|
93
|
+
return Base64.encode64(hmac).strip
|
42
94
|
end
|
43
95
|
end # OTP::Verify
|
44
96
|
end # Yubikey
|
data/spec/hex_spec.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# encoding: US-ASCII
|
3
2
|
describe 'hex' do
|
4
|
-
it '
|
3
|
+
it 'encodes binary to hex' do
|
5
4
|
"i\266H\034\213\253\242\266\016\217\"\027\233X\315V".to_hex.
|
6
5
|
should == '69b6481c8baba2b60e8f22179b58cd56'
|
7
|
-
|
6
|
+
|
8
7
|
"\354\336\030\333\347o\275\f33\017\0345Hq\333".to_hex.
|
9
8
|
should == 'ecde18dbe76fbd0c33330f1c354871db'
|
10
9
|
end
|
11
|
-
|
12
|
-
it '
|
10
|
+
|
11
|
+
it 'decodes hex to binary' do
|
13
12
|
'69b6481c8baba2b60e8f22179b58cd56'.to_bin.
|
14
13
|
should == "i\266H\034\213\253\242\266\016\217\"\027\233X\315V"
|
15
|
-
|
14
|
+
|
16
15
|
'ecde18dbe76fbd0c33330f1c354871db'.to_bin.
|
17
16
|
should == "\354\336\030\333\347o\275\f33\017\0345Hq\333"
|
18
17
|
end
|
19
|
-
|
20
|
-
it '
|
21
|
-
'ecde18dbe76fbd0c33330f1c354871db'.hex?.should
|
22
|
-
'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'.modhex?.should
|
23
|
-
|
24
|
-
'foobar'.hex?.should
|
25
|
-
'test'.modhex?.should
|
18
|
+
|
19
|
+
it 'detects if a string is hex' do
|
20
|
+
'ecde18dbe76fbd0c33330f1c354871db'.hex?.should be_true
|
21
|
+
'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'.modhex?.should be_true
|
22
|
+
|
23
|
+
'foobar'.hex?.should be_false
|
24
|
+
'test'.modhex?.should be_false
|
26
25
|
end
|
27
|
-
end
|
26
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
rescue LoadError
|
4
|
-
require 'rubygems'
|
5
|
-
gem 'rspec'
|
6
|
-
require 'spec'
|
7
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec'
|
8
3
|
|
9
|
-
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
10
5
|
require 'yubikey'
|
metadata
CHANGED
@@ -1,37 +1,24 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: yubikey
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.0
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
|
-
authors:
|
7
|
+
authors:
|
7
8
|
- Jonathan Rudenberg
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
default_executable:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
name: crypt19
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: "0"
|
24
|
-
version:
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
25
14
|
description: A library to verify, decode, decrypt and parse Yubikey one-time passwords.
|
26
15
|
email: jon335@gmail.com
|
27
16
|
executables: []
|
28
|
-
|
29
17
|
extensions: []
|
30
|
-
|
31
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
32
19
|
- LICENSE
|
33
|
-
- README.
|
34
|
-
files:
|
20
|
+
- README.md
|
21
|
+
files:
|
35
22
|
- examples/otp.rb
|
36
23
|
- lib/yubikey.rb
|
37
24
|
- lib/yubikey/hex.rb
|
@@ -39,49 +26,35 @@ files:
|
|
39
26
|
- lib/yubikey/otp.rb
|
40
27
|
- lib/yubikey/otp_verify.rb
|
41
28
|
- spec/hex_spec.rb
|
42
|
-
- spec/spec.opts
|
43
29
|
- spec/spec_helper.rb
|
44
|
-
- spec/yubikey_modhex_spec.rb
|
45
|
-
- spec/yubikey_otp_spec.rb
|
46
|
-
- spec/yubikey_otp_verify_spec.rb
|
47
30
|
- LICENSE
|
48
|
-
- README.
|
49
|
-
|
50
|
-
homepage: http://github.com/titanous/yubikey
|
31
|
+
- README.md
|
32
|
+
homepage: https://github.com/titanous/yubikey
|
51
33
|
licenses: []
|
52
|
-
|
53
34
|
post_install_message:
|
54
|
-
rdoc_options:
|
55
|
-
- --charset=UTF-8
|
35
|
+
rdoc_options:
|
56
36
|
- --title
|
57
37
|
- yubikey
|
58
38
|
- --main
|
59
39
|
- README.rdoc
|
60
|
-
require_paths:
|
40
|
+
require_paths:
|
61
41
|
- lib
|
62
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
74
54
|
requirements: []
|
75
|
-
|
76
55
|
rubyforge_project: yubikey
|
77
|
-
rubygems_version: 1.
|
56
|
+
rubygems_version: 1.8.25
|
78
57
|
signing_key:
|
79
58
|
specification_version: 3
|
80
|
-
summary:
|
81
|
-
test_files:
|
82
|
-
- spec/hex_spec.rb
|
83
|
-
- spec/spec_helper.rb
|
84
|
-
- spec/yubikey_modhex_spec.rb
|
85
|
-
- spec/yubikey_otp_spec.rb
|
86
|
-
- spec/yubikey_otp_verify_spec.rb
|
87
|
-
- examples/otp.rb
|
59
|
+
summary: Yubikey library for Ruby
|
60
|
+
test_files: []
|
data/README.rdoc
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
= yubikey
|
2
|
-
|
3
|
-
== Description
|
4
|
-
|
5
|
-
A library to verify, decode, decrypt and parse Yubikey[http://www.yubico.com/home/index/] one-time passwords.
|
6
|
-
|
7
|
-
== Usage
|
8
|
-
|
9
|
-
=== OTP Decryption
|
10
|
-
|
11
|
-
key = 'ecde18dbe76fbd0c33330f1c354871db'
|
12
|
-
otp = 'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
|
13
|
-
token = Yubikey::OTP.new(otp, key)
|
14
|
-
|
15
|
-
p "Device public id: #{token.public_id}" #=> 'dteffuje'
|
16
|
-
p "Device secret id: #{token.secret_id}" #=> '8792ebfe26cc'
|
17
|
-
p "Device insertions: #{token.insert_counter}" #=> 19
|
18
|
-
p "Session activation counter: #{token.session_counter}" #=> 17
|
19
|
-
p "Session timestamp: #{token.timestamp}" #=> 49712
|
20
|
-
p "OTP random data: #{token.random_number}" #=> 40904
|
21
|
-
|
22
|
-
=== OTP Verification
|
23
|
-
|
24
|
-
begin
|
25
|
-
otp = Yubikey::OTP::Verify.new('dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh')
|
26
|
-
|
27
|
-
if otp.valid?
|
28
|
-
p 'valid OTP'
|
29
|
-
elsif otp.replayed?
|
30
|
-
p 'replayed OTP'
|
31
|
-
end
|
32
|
-
rescue Yubikey::OTP::InvalidOTPError
|
33
|
-
p 'invalid OTP'
|
34
|
-
end
|
35
|
-
|
36
|
-
== Install
|
37
|
-
|
38
|
-
sudo gem install yubikey
|
39
|
-
|
40
|
-
== Copyright
|
41
|
-
|
42
|
-
=== Ruby library
|
43
|
-
Written by Jonathan Rudenberg <jon335@gmail.com>
|
44
|
-
Copyright (c) 2009 Jonathan Rudenberg
|
45
|
-
The MIT License. See LICENSE.
|
46
|
-
|
47
|
-
=== Contributors
|
48
|
-
Carl Byström
|
49
|
-
Erik Ruwalder
|
data/spec/spec.opts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--colour
|
data/spec/yubikey_modhex_spec.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Yubikey::Modhex' do
|
4
|
-
it 'should decode modhex' do
|
5
|
-
Yubikey::ModHex.decode('hknhfjbrjnlnldnhcujvddbikngjrtgh').should == "i\266H\034\213\253\242\266\016\217\"\027\233X\315V"
|
6
|
-
Yubikey::ModHex.decode('urtubjtnuihvntcreeeecvbregfjibtn').should == "\354\336\030\333\347o\275\f33\017\0345Hq\333"
|
7
|
-
|
8
|
-
Yubikey::ModHex.decode('dteffuje').should == "-4N\203"
|
9
|
-
|
10
|
-
Yubikey::ModHex.decode('ifhgieif').should == 'test'
|
11
|
-
Yubikey::ModHex.decode('hhhvhvhdhbid').should == 'foobar'
|
12
|
-
|
13
|
-
Yubikey::ModHex.decode('cc').should == "\000"
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should raise if modhex string length uneven' do
|
17
|
-
lambda { Yubikey::ModHex.decode('ifh') }.should raise_error(ArgumentError)
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should encode modhex' do
|
21
|
-
Yubikey::ModHex.encode("i\266H\034\213\253\242\266\016\217\"\027\233X\315V").should == 'hknhfjbrjnlnldnhcujvddbikngjrtgh'
|
22
|
-
Yubikey::ModHex.encode("\354\336\030\333\347o\275\f33\017\0345Hq\333").should == 'urtubjtnuihvntcreeeecvbregfjibtn'
|
23
|
-
|
24
|
-
Yubikey::ModHex.encode("-4N\203").should == 'dteffuje'
|
25
|
-
|
26
|
-
Yubikey::ModHex.encode('test').should == 'ifhgieif'
|
27
|
-
Yubikey::ModHex.encode('foobar').should == 'hhhvhvhdhbid'
|
28
|
-
|
29
|
-
Yubikey::ModHex.encode("\000").should == 'cc'
|
30
|
-
end
|
31
|
-
end
|
data/spec/yubikey_otp_spec.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Yubikey::OTP' do
|
4
|
-
it 'should parse a otp' do
|
5
|
-
token = Yubikey::OTP.new('dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh', 'ecde18dbe76fbd0c33330f1c354871db')
|
6
|
-
|
7
|
-
token.public_id.should == 'dteffuje'
|
8
|
-
token.secret_id.should == '8792ebfe26cc'
|
9
|
-
token.insert_counter.should == 19
|
10
|
-
token.session_counter.should == 17
|
11
|
-
token.timestamp.should == 49712
|
12
|
-
token.random_number.should == 40904
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'should raise if key or otp invalid' do
|
16
|
-
otp = 'hknhfjbrjnlnldnhcujvddbikngjrtgh'
|
17
|
-
key = 'ecde18dbe76fbd0c33330f1c354871db'
|
18
|
-
|
19
|
-
lambda { Yubikey::OTP.new(key, key) }.should raise_error(Yubikey::OTP::InvalidOTPError)
|
20
|
-
lambda { Yubikey::OTP.new(otp, otp) }.should raise_error(Yubikey::OTP::InvalidKeyError)
|
21
|
-
|
22
|
-
lambda { Yubikey::OTP.new(otp[0,31], key) }.should raise_error(Yubikey::OTP::InvalidOTPError)
|
23
|
-
lambda { Yubikey::OTP.new(otp, key[0,31]) }.should raise_error(Yubikey::OTP::InvalidKeyError)
|
24
|
-
|
25
|
-
lambda { Yubikey::OTP.new(otp[1,31]+'d', key) }.should raise_error(Yubikey::OTP::BadCRCError)
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
-
|
3
|
-
describe 'Yubikey::OTP::Verify' do
|
4
|
-
|
5
|
-
before do
|
6
|
-
@otp = 'dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh'
|
7
|
-
|
8
|
-
@mock_http = mock('http')
|
9
|
-
@mock_http_get = mock('http_get')
|
10
|
-
|
11
|
-
Net::HTTP.should_receive(:new).with('api.yubico.com', 443).and_return(@mock_http)
|
12
|
-
@mock_http.should_receive(:use_ssl=).and_return(nil)
|
13
|
-
@mock_http.should_receive(:verify_mode=).and_return(nil)
|
14
|
-
@mock_http.should_receive(:request).with(@mock_http_get).and_return(@mock_http_get)
|
15
|
-
Net::HTTP::Get.should_receive(:new).with(/otp=#{@otp}/).and_return(@mock_http_get)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should verify a valid OTP' do
|
19
|
-
@mock_http_get.should_receive(:body).and_return('status=OK')
|
20
|
-
otp = Yubikey::OTP::Verify.new(@otp)
|
21
|
-
otp.valid?.should == true
|
22
|
-
otp.replayed?.should == false
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should verify a replayed OTP' do
|
26
|
-
@mock_http_get.should_receive(:body).and_return('status=REPLAYED_OTP')
|
27
|
-
otp = Yubikey::OTP::Verify.new(@otp)
|
28
|
-
otp.valid?.should == false
|
29
|
-
otp.replayed?.should == true
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should raise on invalid OTP' do
|
33
|
-
@mock_http_get.should_receive(:body).and_return('status=BAD_OTP')
|
34
|
-
lambda { otp = Yubikey::OTP::Verify.new(@otp) }.should raise_error(Yubikey::OTP::InvalidOTPError)
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
end
|