motp 1.0.2
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/.gitignore +3 -0
- data/Gemfile +4 -0
- data/README.md +66 -0
- data/Rakefile +2 -0
- data/lib/motp.rb +14 -0
- data/lib/motp/version.rb +3 -0
- data/motp.gemspec +21 -0
- data/test/motp_test.rb +58 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
MOTP
|
2
|
+
====
|
3
|
+
|
4
|
+
This RubyGem implements the [Mobile-OTP standard](http://motp.sourceforge.net/) in Ruby,
|
5
|
+
allowing you to write Ruby (and Rails) powered servers and client implementations. This
|
6
|
+
enables you, for example, to implement strong two-factor authentication into your web
|
7
|
+
application, where your users use their mobile phones as a remote token.
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
|
12
|
+
gem install motp
|
13
|
+
|
14
|
+
Server Implementation
|
15
|
+
---------------------
|
16
|
+
|
17
|
+
For each user, come up with a secret and allow them to specify their PIN. Store both.
|
18
|
+
When they use your system, ask them for the One-Time Pad. They can get this by using
|
19
|
+
their mobile phone (which they've already configured with the secret) and entering their
|
20
|
+
PIN.
|
21
|
+
|
22
|
+
require 'motp'
|
23
|
+
|
24
|
+
MOTP::check(secret, pin, otp)
|
25
|
+
|
26
|
+
Returns true if the otp is valid for the specified secret and PIN, false otherwise.
|
27
|
+
|
28
|
+
OTPs are based on the UTC clock and are valid (by default) for three minutes before and
|
29
|
+
three minutes after they were requested, in order to accomodate the time taken to type
|
30
|
+
in the OTP, and possible variations in the accuracy of the system clocks on the server
|
31
|
+
and the client (mobile phone) devices.
|
32
|
+
|
33
|
+
Optional parameters (appended to the end):
|
34
|
+
|
35
|
+
* :time => specifies the time for which the OTP must be valid; defaults to "now"
|
36
|
+
* :max_period => specifies the number of seconds of leeway, ahead and behind, during which an OTP is considered valid - defaults to 3 * 60 (3 minutes)
|
37
|
+
|
38
|
+
Client Implementation
|
39
|
+
---------------------
|
40
|
+
|
41
|
+
If you want to write a mobile MOTP client in Ruby, go ahead! The MOTP RubyGem supports
|
42
|
+
this too.
|
43
|
+
|
44
|
+
require 'motp'
|
45
|
+
|
46
|
+
MOTP::otp(secret, pin)
|
47
|
+
|
48
|
+
Returns the OTP for the current time. As with the server implementation, you can pass an
|
49
|
+
optional :time parameter to specify the time for wich you want to generate, but you
|
50
|
+
shouldn't ever need to do this unless you *know* the device clock to be incorrect.
|
51
|
+
|
52
|
+
License
|
53
|
+
-------
|
54
|
+
|
55
|
+
This program is free software: you can redistribute it and/or modify
|
56
|
+
it under the terms of the GNU General Public License as published by
|
57
|
+
the Free Software Foundation, either version 3 of the License, or
|
58
|
+
(at your option) any later version.
|
59
|
+
|
60
|
+
This program is distributed in the hope that it will be useful,
|
61
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
62
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
63
|
+
GNU General Public License for more details.
|
64
|
+
|
65
|
+
You should have received a copy of the GNU General Public License
|
66
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
data/Rakefile
ADDED
data/lib/motp.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Motp
|
4
|
+
def self.otp(secret, pin, options = {})
|
5
|
+
options = {:time => Time::now}.merge(options)
|
6
|
+
Digest::MD5::hexdigest("#{options[:time].utc.tv_sec.to_s[0...-1]}#{secret}#{pin}")[0,6]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.check(secret, pin, otp, options = {})
|
10
|
+
options = {:time => Time::now, :max_period => (3 * 60)}.merge(options)
|
11
|
+
range = ((options[:time] - options[:max_period])..(options[:time] + options[:max_period]))
|
12
|
+
return range.any?{|time| otp == self.otp(secret, pin, :time => time)}
|
13
|
+
end
|
14
|
+
end
|
data/lib/motp/version.rb
ADDED
data/motp.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "motp/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "motp"
|
7
|
+
s.version = Motp::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Dan Q"]
|
10
|
+
s.email = ["dan@scatmania.org"]
|
11
|
+
s.homepage = "http://www.scatmania.org/projects/motp"
|
12
|
+
s.summary = %q{Methods for implementing a Mobile One-Time Pad client or server in Ruby.}
|
13
|
+
s.description = %q{Methods for implementing a Mobile One-Time Pad client or server in Ruby.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "motp"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
data/test/motp_test.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'lib/motp'
|
3
|
+
|
4
|
+
class MOTP_Test < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@secret = 'secret12345'
|
7
|
+
@pin = '1234'
|
8
|
+
@valid_otp_regex = /^[\da-f]{6}$/
|
9
|
+
end
|
10
|
+
|
11
|
+
# def teardown
|
12
|
+
# end
|
13
|
+
|
14
|
+
def test_otp_matches_regex
|
15
|
+
otp_now = MOTP::otp(@secret, @pin)
|
16
|
+
assert(otp_now =~ @valid_otp_regex)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_now
|
20
|
+
otp_now = MOTP::otp(@secret, @pin)
|
21
|
+
assert(MOTP::check(@secret, @pin, otp_now))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_2min_ago
|
25
|
+
otp = MOTP::otp(@secret, @pin, :time => Time::now - (2*60))
|
26
|
+
assert(MOTP::check(@secret, @pin, otp))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_4min_ago_fails
|
30
|
+
otp = MOTP::otp(@secret, @pin, :time => Time::now - (4*60))
|
31
|
+
assert(!MOTP::check(@secret, @pin, otp))
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_2min_ahead
|
35
|
+
otp = MOTP::otp(@secret, @pin, :time => Time::now + (2*60))
|
36
|
+
assert(MOTP::check(@secret, @pin, otp))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_4min_ahead_fails
|
40
|
+
otp = MOTP::otp(@secret, @pin, :time => Time::now + (4*60))
|
41
|
+
assert(!MOTP::check(@secret, @pin, otp))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_various_random_otps_fail
|
45
|
+
['', '123456', 'abcdef', 'alpha' 'letmein!'].each do |otp|
|
46
|
+
assert(!MOTP::check(@secret, @pin, otp))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_specific_known_good_case
|
51
|
+
time = Time::utc(2011, 1, 20, 14, 28, 23)
|
52
|
+
secret, pin = 'abcd1234', '1234'
|
53
|
+
valid_otp = '6f8af8'
|
54
|
+
invalid_otp = '5d60af'
|
55
|
+
assert(MOTP::check(secret, pin, valid_otp, :time => time))
|
56
|
+
assert(!MOTP::check(secret, pin, invalid_otp, :time => time))
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 1.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dan Q
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-30 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Methods for implementing a Mobile One-Time Pad client or server in Ruby.
|
22
|
+
email:
|
23
|
+
- dan@scatmania.org
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- lib/motp.rb
|
36
|
+
- lib/motp/version.rb
|
37
|
+
- motp.gemspec
|
38
|
+
- test/motp_test.rb
|
39
|
+
homepage: http://www.scatmania.org/projects/motp
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
hash: 3
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: motp
|
68
|
+
rubygems_version: 1.8.11
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Methods for implementing a Mobile One-Time Pad client or server in Ruby.
|
72
|
+
test_files:
|
73
|
+
- test/motp_test.rb
|