rotp 2.1.1 → 6.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rotp might be problematic. Click here for more details.

Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/.devcontainer/Dockerfile +19 -0
  3. data/.devcontainer/devcontainer.json +37 -0
  4. data/.dockerignore +1 -0
  5. data/.github/workflows/test.yaml +27 -0
  6. data/.gitignore +2 -0
  7. data/CHANGELOG.md +95 -0
  8. data/Dockerfile-2.3 +10 -0
  9. data/Dockerfile-2.7 +11 -0
  10. data/Dockerfile-3.0-rc +12 -0
  11. data/Guardfile +1 -1
  12. data/README.md +125 -31
  13. data/bin/rotp +1 -1
  14. data/docker-compose.yml +37 -0
  15. data/lib/rotp/arguments.rb +6 -5
  16. data/lib/rotp/base32.rb +56 -29
  17. data/lib/rotp/cli.rb +6 -10
  18. data/lib/rotp/hotp.rb +11 -26
  19. data/lib/rotp/otp/uri.rb +79 -0
  20. data/lib/rotp/otp.rb +20 -31
  21. data/lib/rotp/totp.rb +43 -29
  22. data/lib/rotp/version.rb +1 -1
  23. data/lib/rotp.rb +2 -3
  24. data/rotp.gemspec +15 -18
  25. data/spec/lib/rotp/arguments_spec.rb +18 -5
  26. data/spec/lib/rotp/base32_spec.rb +51 -19
  27. data/spec/lib/rotp/cli_spec.rb +42 -3
  28. data/spec/lib/rotp/hotp_spec.rb +39 -60
  29. data/spec/lib/rotp/otp/uri_spec.rb +99 -0
  30. data/spec/lib/rotp/totp_spec.rb +138 -120
  31. data/spec/spec_helper.rb +7 -0
  32. metadata +27 -45
  33. data/.travis.yml +0 -7
  34. data/Gemfile.lock +0 -75
  35. data/Rakefile +0 -9
  36. data/doc/ROTP/HOTP.html +0 -308
  37. data/doc/ROTP/OTP.html +0 -593
  38. data/doc/ROTP/TOTP.html +0 -493
  39. data/doc/Rotp.html +0 -179
  40. data/doc/_index.html +0 -144
  41. data/doc/class_list.html +0 -36
  42. data/doc/css/common.css +0 -1
  43. data/doc/css/full_list.css +0 -53
  44. data/doc/css/style.css +0 -310
  45. data/doc/file.README.html +0 -89
  46. data/doc/file_list.html +0 -38
  47. data/doc/frames.html +0 -13
  48. data/doc/index.html +0 -89
  49. data/doc/js/app.js +0 -203
  50. data/doc/js/full_list.js +0 -149
  51. data/doc/js/jquery.js +0 -154
  52. data/doc/method_list.html +0 -155
  53. data/doc/top-level-namespace.html +0 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2725d64c9f5c1dd2c64165cced04357972e269c2
4
- data.tar.gz: 4396a34a9e33102c800cfcc7815db87fcf1c612a
2
+ SHA256:
3
+ metadata.gz: 4ce425976dcf66314bf7217e6c5901c8e4cfd54d78919c058052ec2fc1d8c336
4
+ data.tar.gz: 6d0c496074dbe1d6d625e26b0408e33585c9783661077f322e7aa4c3585442c8
5
5
  SHA512:
6
- metadata.gz: fb6e0c9f09dc0bb9a48d53dd883ad53be3ea63b1fe0abddf8370537ccd859d5826c6a95570dc4a647c4f8592ae9520e3bf5bd2f073beb3f82cc07274cc93de27
7
- data.tar.gz: 7af5f0b49b5b1de78dad69d89b4b52a4369f79304b8d48f47a9f760f46839705c6359d1af5475476d0d31b85614488f34a63ad0213134ba74f95998a8cb1f441
6
+ metadata.gz: f4d739d3cc3fed5ec4cdcd04b6c73b8fa30cfdc513d92f4e8c1130f45682b2aa37cd2029f66522c0648a8a8d3a905556e1ac1b42715f6ef6f2e95716dd010422
7
+ data.tar.gz: ada9184523ddc259caabedb7429704d7a952b19faf067dbdc6a65d29dbdb57f3ad4a0e4a9e9b07268518f6f239190882b0f9cfc60b39264f7b79b381566c436c
@@ -0,0 +1,19 @@
1
+ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ruby/.devcontainer/base.Dockerfile
2
+
3
+ # [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.1, 3.0, 2, 2.7, 3-bullseye, 3.1-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 3-buster, 3.1-buster, 3.0-buster, 2-buster, 2.7-buster
4
+ ARG VARIANT="3.1-bullseye"
5
+ FROM mcr.microsoft.com/vscode/devcontainers/ruby:0-${VARIANT}
6
+
7
+ # [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
8
+ ARG NODE_VERSION="none"
9
+ RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
10
+
11
+ # [Optional] Uncomment this section to install additional OS packages.
12
+ # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
13
+ # && apt-get -y install --no-install-recommends <your-package-list-here>
14
+
15
+ # [Optional] Uncomment this line to install additional gems.
16
+ # RUN gem install <your-gem-names-here>
17
+
18
+ # [Optional] Uncomment this line to install global node packages.
19
+ # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
@@ -0,0 +1,37 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
2
+ // https://github.com/microsoft/vscode-dev-containers/tree/v0.238.1/containers/ruby
3
+ {
4
+ "name": "Ruby",
5
+ "build": {
6
+ "dockerfile": "Dockerfile",
7
+ "args": {
8
+ // Update 'VARIANT' to pick a Ruby version: 3, 3.1, 3.0, 2, 2.7
9
+ // Append -bullseye or -buster to pin to an OS version.
10
+ // Use -bullseye variants on local on arm64/Apple Silicon.
11
+ "VARIANT": "3-bullseye",
12
+ // Options
13
+ "NODE_VERSION": "16"
14
+ }
15
+ },
16
+
17
+ // Configure tool-specific properties.
18
+ "customizations": {
19
+ // Configure properties specific to VS Code.
20
+ "vscode": {
21
+ // Add the IDs of extensions you want installed when the container is created.
22
+ "extensions": [
23
+ "rebornix.Ruby"
24
+ ]
25
+ }
26
+ },
27
+
28
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
29
+ // "forwardPorts": [],
30
+
31
+ // Use 'postCreateCommand' to run commands after the container is created.
32
+ // "postCreateCommand": "ruby --version",
33
+
34
+ // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
35
+ "remoteUser": "vscode"
36
+
37
+ }
data/.dockerignore ADDED
@@ -0,0 +1 @@
1
+ Dockerfile*
@@ -0,0 +1,27 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ ruby-version: ['3.1', '3.0', '2.7', '2.3']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v3
20
+ - name: Set up Ruby ${{ matrix.ruby-version }}
21
+ uses: ruby/setup-ruby@359bebbc29cbe6c87da6bc9ea3bc930432750108
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ - name: Install dependencies
25
+ run: bundle install
26
+ - name: Run tests
27
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  .bundle
3
3
  .yardoc
4
4
  pkg/*
5
+ coverage
6
+ Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -1,5 +1,100 @@
1
1
  ### Changelog
2
2
 
3
+ ### 6.2.2
4
+
5
+ - Removed `rjust` from `generate_otp` in favor of more time constant version
6
+
7
+ ### 6.2.1
8
+
9
+ - Removed old rdoc folder that was triggering a security warning due to an
10
+ old version of JQuery being included in the HTML docs. This has no impact
11
+ on the Ruby library.
12
+
13
+ ### 6.2.0
14
+
15
+ - Update to expand compatibility with Ruby 3. This was only a change to the
16
+ gemspec, no code changes were necessary.
17
+
18
+ ### 6.1.0
19
+
20
+ - Fixing URI encoding issues again, breaking out into it's own module
21
+ due to the complexity - closes #100 (@atcruice)
22
+ - Add docker-compose.yml to help with easier testing
23
+
24
+ ### 6.0.0
25
+
26
+ - Dropping support for Ruby <2.3 (Major version bump)
27
+ - Fix issue when using --enable-frozen-string-literal Ruby option #95 (jeremyevans)
28
+ - URI Encoding fix #94 (ksuh90)
29
+ - Update gems (rake, addressable)
30
+ - Update Travis tests to include Ruby 2.7
31
+
32
+ ### 5.1.0
33
+
34
+ - Create `random_base32` to perform `random` to avoid breaking changes
35
+ - Still needed to bump to 5.x due to Base32 cleanup
36
+
37
+ ### 5.0.0
38
+
39
+ - Clean up base32 implementation to match Google Autheticator
40
+ - BREAKING `Base32.random_base32` renamed to random
41
+ - The argument is now byte length vs output string length for more precise bit strengths
42
+
43
+ ### 4.1.0
44
+
45
+ - Add a digest option to the CLI #83
46
+ - Fix provisioning URI is README #82
47
+ - Improvements to docs
48
+
49
+ ### 4.0.2
50
+
51
+ - Fix gemspec requirment for Addressable
52
+
53
+ ### 4.0.1
54
+
55
+ - Rubocop for style fixes
56
+ - Replace deprecated URI.encode with Addressable's version
57
+
58
+ #### 4.0.0
59
+
60
+ - Simplify API
61
+ - Remove support for Ruby < 2.0
62
+ - BREAKING CHANGE: Removed optional second argument (`padding`) from:
63
+ - `HOTP#at`
64
+ - `OTP#generate_otp`
65
+ - `TOTP#at`
66
+ - `TOTP#now` (first argument)
67
+
68
+ #### 3.3.1
69
+
70
+ - Add OpenSSL as a requirement for Ruby 2.5. Fixes #70 & #64
71
+ - Allow Base32 with padding. #71
72
+ - Prevent verify with drift being negative #69
73
+
74
+ #### 3.3.0
75
+
76
+ - Add digest algorithm parameter for non SHA1 digests - #62 from @btalbot
77
+
78
+ #### 3.2.0
79
+
80
+ - Add 'verify_with_drift_and_prior' to prevent prior token use - #58 from @jlfaber
81
+
82
+ #### 3.1.0
83
+
84
+ - Add Add digits paramater to provisioning URI. #54 from @sbc100
85
+
86
+ #### 3.0.1
87
+
88
+ - Use SecureRandom. See mdp/rotp/pull/52
89
+
90
+ #### 3.0.0
91
+
92
+ - Provisioning URL includes issuer label per RFC 5234 See mdp/rotp/pull/51
93
+
94
+ #### 2.1.2
95
+
96
+ - Remove string literals to prepare immutable strings in Ruby 3.0
97
+
3
98
  #### 2.1.1
4
99
 
5
100
  - Reorder the params for Windows Phone Authenticator - #43
data/Dockerfile-2.3 ADDED
@@ -0,0 +1,10 @@
1
+ FROM ruby:2.3
2
+
3
+ RUN mkdir -p /usr/src/app
4
+ WORKDIR /usr/src/app
5
+
6
+ COPY Gemfile /usr/src/app/
7
+ COPY . /usr/src/app
8
+ RUN bundle install
9
+
10
+ CMD ["bundle", "exec", "rspec"]
data/Dockerfile-2.7 ADDED
@@ -0,0 +1,11 @@
1
+ FROM ruby:2.7
2
+
3
+ RUN mkdir -p /usr/src/app
4
+ WORKDIR /usr/src/app
5
+
6
+ COPY Gemfile /usr/src/app/
7
+ COPY . /usr/src/app
8
+ RUN bundle install
9
+
10
+ CMD ["bundle", "exec", "rspec"]
11
+
data/Dockerfile-3.0-rc ADDED
@@ -0,0 +1,12 @@
1
+ FROM ruby:3.0-rc
2
+
3
+ RUN mkdir -p /usr/src/app
4
+ WORKDIR /usr/src/app
5
+
6
+ COPY Gemfile /usr/src/app/
7
+ COPY . /usr/src/app
8
+ RUN gem install bundler
9
+ RUN bundle install
10
+
11
+ CMD ["bundle", "exec", "rspec"]
12
+
data/Guardfile CHANGED
@@ -1,5 +1,5 @@
1
1
  guard :rspec, cmd: 'bundle exec rspec --format progress' do
2
- require "guard/rspec/dsl"
2
+ require 'guard/rspec/dsl'
3
3
  dsl = Guard::RSpec::Dsl.new(self)
4
4
 
5
5
  # RSpec files
data/README.md CHANGED
@@ -1,19 +1,54 @@
1
+ ## Webauthn and the future of 2FA
2
+
3
+ Although this library will continue to be maintained, if you're implementing a 2FA solution today, you should take a look at [Webauthn](https://webauthn.guide/). It doesn't involve shared secrets and it's supported by most modern browsers and operating systems.
4
+
5
+ ### Ruby resources for Webauthn
6
+
7
+ - [Multi-Factor Authentication for Rails With WebAuthn and Devise](https://www.honeybadger.io/blog/multi-factor-2fa-authentication-rails-webauthn-devise/)
8
+ - [Webauthn Ruby Gem](https://github.com/cedarcode/webauthn-ruby)
9
+ - [Rails demo app with Webauthn](https://github.com/cedarcode/webauthn-rails-demo-app)
10
+
11
+ ----
12
+
1
13
  # The Ruby One Time Password Library
2
14
 
3
- [![Build Status](https://secure.travis-ci.org/mdp/rotp.png)](https://travis-ci.org/mdp/rotp)
15
+ [![Build Status](https://github.com/mdp/rotp/actions/workflows/test.yaml/badge.svg)](https://github.com/mdp/rotp/actions/workflows/test.yaml)
4
16
  [![Gem Version](https://badge.fury.io/rb/rotp.svg)](https://rubygems.org/gems/rotp)
17
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](https://www.rubydoc.info/github/mdp/rotp/master)
5
18
  [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/mdp/rotp/blob/master/LICENSE)
6
19
 
7
- A ruby library for generating one time passwords (HOTP & TOTP) according to [RFC 4226](http://tools.ietf.org/html/rfc4226) and [RFC 6238](http://tools.ietf.org/html/rfc6238).
8
20
 
9
- ROTP is compatible with the [Google Authenticator](https://github.com/google/google-authenticator) available for [Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) and [iPhone](https://itunes.apple.com/en/app/google-authenticator/id388497605).
21
+ A ruby library for generating and validating one time passwords (HOTP & TOTP) according to [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226) and [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238).
22
+
23
+ ROTP is compatible with [Google Authenticator](https://github.com/google/google-authenticator) available for [Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) and [iPhone](https://itunes.apple.com/en/app/google-authenticator/id388497605) and any other TOTP based implementations.
10
24
 
11
- Many websites use this for [multi-factor authentication](https://www.youtube.com/watch?v=17rykTIX_HY), such as GMail, Facebook, Amazon EC2, WordPress, and Salesforce. You can find the whole [list here](https://en.wikipedia.org/wiki/Google_Authenticator#Usage).
25
+ Many websites use this for [multi-factor authentication](https://www.youtube.com/watch?v=17rykTIX_HY), such as GMail, Facebook, Amazon EC2, WordPress, and Salesforce. You can find a more complete [list here](https://en.wikipedia.org/wiki/Google_Authenticator#Usage).
12
26
 
13
27
  ## Dependencies
14
28
 
15
29
  * OpenSSL
16
- * Ruby 1.9.3 or higher
30
+ * Ruby 2.3 or higher
31
+
32
+ ## Breaking changes
33
+
34
+ ### Breaking changes in >= 6.0
35
+
36
+ - Dropping support for Ruby <2.3
37
+
38
+ ### Breaking changes in >= 5.0
39
+
40
+ - `ROTP::Base32.random_base32` is now `ROTP::Base32.random` and the argument
41
+ has changed from secret string length to byte length to allow for more
42
+ precision. There is an alias to allow for `random_base32` for the time being.
43
+ - Cleaned up the Base32 implementation to match Google Authenticator's version.
44
+
45
+ ### Breaking changes in >= 4.0
46
+
47
+ - Simplified API
48
+ - `verify` now takes options for `drift` and `after`,`padding` is no longer an option
49
+ - `verify` returns a timestamp if true, nil if false
50
+ - Dropping support for Ruby < 2.0
51
+ - Docs for 3.x can be found [here](https://github.com/mdp/rotp/tree/v3.x)
17
52
 
18
53
  ## Installation
19
54
 
@@ -26,60 +61,104 @@ gem install rotp
26
61
  ### Time based OTP's
27
62
 
28
63
  ```ruby
29
- totp = ROTP::TOTP.new("base32secret3232")
64
+ totp = ROTP::TOTP.new("base32secret3232", issuer: "My Service")
30
65
  totp.now # => "492039"
31
66
 
32
- # OTP verified for current time
33
- totp.verify("492039") # => true
34
- sleep 30
35
- totp.verify("492039") # => false
36
- ```
67
+ # OTP verified for current time - returns timestamp of the current interval
68
+ # period.
69
+ totp.verify("492039") # => 1474590700
37
70
 
38
- Optionally, you can provide an issuer which will be used as a title in Google Authenticator.
71
+ sleep 30
39
72
 
40
- ```ruby
41
- totp = ROTP::TOTP.new("base32secret3232", issuer: "My Service")
73
+ # OTP fails to verify - returns nil
74
+ totp.verify("492039") # => nil
42
75
  ```
43
76
 
44
77
  ### Counter based OTP's
45
78
 
46
79
  ```ruby
47
80
  hotp = ROTP::HOTP.new("base32secretkey3232")
48
- hotp.at(0) # => "260182"
49
- hotp.at(1) # => "055283"
50
- hotp.at(1401) # => "316439"
81
+ hotp.at(0) # => "786922"
82
+ hotp.at(1) # => "595254"
83
+ hotp.at(1401) # => "259769"
51
84
 
52
85
  # OTP verified with a counter
53
- hotp.verify("316439", 1401) # => true
54
- hotp.verify("316439", 1402) # => false
86
+ hotp.verify("259769", 1401) # => 1401
87
+ hotp.verify("259769", 1402) # => nil
88
+ ```
89
+
90
+ ### Preventing reuse of Time based OTP's
91
+
92
+ By keeping track of the last time a user's OTP was verified, we can prevent token reuse during
93
+ the interval window (default 30 seconds)
94
+
95
+ The following is an example of this in action:
96
+
97
+ ```ruby
98
+ user = User.find(someUserID)
99
+ totp = ROTP::TOTP.new(user.otp_secret)
100
+ totp.now # => "492039"
101
+
102
+ # Let's take a look at the last time the user authenticated with an OTP
103
+ user.last_otp_at # => 1432703530
104
+
105
+ # Verify the OTP
106
+ last_otp_at = totp.verify("492039", after: user.last_otp_at) #=> 1472145760
107
+ # ROTP returns the timestamp(int) of the current period
108
+
109
+ # Store this on the user's account
110
+ user.update(last_otp_at: last_otp_at)
111
+
112
+ # Someone attempts to reuse the OTP inside the 30s window
113
+ last_otp_at = totp.verify("492039", after: user.last_otp_at) #=> nil
114
+ # It fails to verify because we are still in the same 30s interval window
115
+ ```
116
+
117
+ ### Verifying a Time based OTP with drift
118
+
119
+ Some users may enter a code just after it has expired. By adding 'drift' you can allow
120
+ for a recently expired token to remain valid.
121
+
122
+ ```ruby
123
+ totp = ROTP::TOTP.new("base32secret3232")
124
+ now = Time.at(1474590600) #2016-09-23 00:30:00 UTC
125
+ totp.at(now) # => "250939"
126
+
127
+ # OTP verified for current time along with 15 seconds earlier
128
+ # ie. User enters a code just after it expired
129
+ totp.verify("250939", drift_behind: 15, at: now + 35) # => 1474590600
130
+ # User waits too long. Fails to validate previous OTP
131
+ totp.verify("250939", drift_behind: 15, at: now + 45) # => nil
55
132
  ```
56
133
 
57
134
  ### Generating a Base32 Secret key
58
135
 
59
136
  ```ruby
60
- ROTP::Base32.random_base32 # returns a 16 character base32 secret. Compatible with Google Authenticator
137
+ ROTP::Base32.random # returns a 160 bit (32 character) base32 secret. Compatible with Google Authenticator
61
138
  ```
62
139
 
63
140
  Note: The Base32 format conforms to [RFC 4648 Base32](http://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet)
64
141
 
65
- ### Google Authenticator Compatible URI's
142
+ ### Generating QR Codes for provisioning mobile apps
66
143
 
67
- Provisioning URI's generated by ROTP are compatible with the Google Authenticator App
68
- to be scanned with the in-built QR Code scanner.
144
+ Provisioning URI's generated by ROTP are compatible with most One Time Password applications, including
145
+ Google Authenticator.
69
146
 
70
147
  ```ruby
71
- totp.provisioning_uri("alice@google.com") # => 'otpauth://totp/alice@google.com?secret=JBSWY3DPEHPK3PXP'
72
- hotp.provisioning_uri("alice@google.com", 0) # => 'otpauth://hotp/alice@google.com?secret=JBSWY3DPEHPK3PXP&counter=0'
148
+ totp = ROTP::TOTP.new("base32secret3232", issuer: "My Service")
149
+ totp.provisioning_uri("alice@google.com") # => 'otpauth://totp/My%20Service:alice%40google.com?secret=base32secret3232&issuer=My%20Service'
150
+
151
+ hotp = ROTP::HOTP.new("base32secret3232", issuer: "My Service")
152
+ hotp.provisioning_uri("alice@google.com", 0) # => 'otpauth://hotp/alice%40google.com?secret=base32secret3232&counter=0'
73
153
  ```
74
154
 
75
- This can then be rendered as a QR Code which can then be scanned and added to the users
76
- list of OTP credentials.
155
+ This can then be rendered as a QR Code which the user can scan using their mobile phone and the appropriate application.
77
156
 
78
157
  #### Working example
79
158
 
80
159
  Scan the following barcode with your phone, using Google Authenticator
81
160
 
82
- ![QR Code for OTP](http://chart.apis.google.com/chart?cht=qr&chs=250x250&chl=otpauth%3A%2F%2Ftotp%2Falice%40google.com%3Fsecret%3DJBSWY3DPEHPK3PXP)
161
+ ![QR Code for OTP](https://cloud.githubusercontent.com/assets/2868/18771262/54f109dc-80f2-11e6-863f-d2be62ee587a.png)
83
162
 
84
163
  Now run the following and compare the output
85
164
 
@@ -97,10 +176,25 @@ bundle install
97
176
  bundle exec rspec
98
177
  ```
99
178
 
179
+ ### Testing with Docker
180
+
181
+ In order to make it easier to test against different ruby version, ROTP comes
182
+ with a set of Dockerfiles for each version that we test against in Travis
183
+
184
+ ```bash
185
+ docker build -f Dockerfile-2.6 -t rotp_2.6 .
186
+ docker run --rm -v $(pwd):/usr/src/app rotp_2.6
187
+ ```
188
+
189
+ Alternately, you may use docker-compose to run all the tests:
190
+
191
+ ```
192
+ docker-compose up
193
+ ```
194
+
100
195
  ## Executable Usage
101
196
 
102
- Once the rotp rubygem is installed on your system, you should be able to run the `rotp` executable
103
- (if not, you might find trouble-shooting help [at this stackoverflow question](http://stackoverflow.com/a/909980)).
197
+ The rotp rubygem includes CLI version to help with testing and debugging
104
198
 
105
199
  ```bash
106
200
  # Try this to get an overview of the commands
@@ -117,7 +211,7 @@ Have a look at the [contributors graph](https://github.com/mdp/rotp/graphs/contr
117
211
 
118
212
  ## License
119
213
 
120
- MIT Copyright (C) 2011 by Mark Percival, see [LICENSE](https://github.com/mdp/rotp/blob/master/LICENSE) for details.
214
+ MIT Copyright (C) 2019 by Mark Percival, see [LICENSE](https://github.com/mdp/rotp/blob/master/LICENSE) for details.
121
215
 
122
216
  ## Other implementations
123
217
 
data/bin/rotp CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $: << File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH << File.expand_path('../lib', __dir__)
4
4
  require 'rotp'
5
5
  require 'rotp/cli'
6
6
 
@@ -0,0 +1,37 @@
1
+ version: "3.8"
2
+ services:
3
+ ruby_2_3:
4
+ build:
5
+ context: .
6
+ dockerfile: Dockerfile-2.3
7
+ volumes:
8
+ - "./lib:/usr/src/app/lib"
9
+ - "./spec:/usr/src/app/spec"
10
+ ruby_2_5:
11
+ build:
12
+ context: .
13
+ dockerfile: Dockerfile-2.5
14
+ volumes:
15
+ - "./lib:/usr/src/app/lib"
16
+ - "./spec:/usr/src/app/spec"
17
+ ruby_2_6:
18
+ build:
19
+ context: .
20
+ dockerfile: Dockerfile-2.6
21
+ volumes:
22
+ - "./lib:/usr/src/app/lib"
23
+ - "./spec:/usr/src/app/spec"
24
+ ruby_2_7:
25
+ build:
26
+ context: .
27
+ dockerfile: Dockerfile-2.7
28
+ volumes:
29
+ - "./lib:/usr/src/app/lib"
30
+ - "./spec:/usr/src/app/spec"
31
+ ruby_3_0_rc:
32
+ build:
33
+ context: .
34
+ dockerfile: Dockerfile-3.0-rc
35
+ volumes:
36
+ - "./lib:/usr/src/app/lib"
37
+ - "./spec:/usr/src/app/spec"
@@ -3,7 +3,6 @@ require 'ostruct'
3
3
 
4
4
  module ROTP
5
5
  class Arguments
6
-
7
6
  def initialize(filename, arguments)
8
7
  @filename = filename
9
8
  @arguments = Array(arguments)
@@ -32,11 +31,11 @@ module ROTP
32
31
 
33
32
  def parse
34
33
  return options!.mode = :help if arguments.empty?
35
- parser.parse arguments
36
34
 
35
+ parser.parse arguments
37
36
  rescue OptionParser::InvalidOption => exception
38
37
  options!.mode = :help
39
- options!.warnings = red(exception.message + '. Try --help for help.')
38
+ options!.warnings = red(exception.message + '. Try --help for help.')
40
39
  end
41
40
 
42
41
  def parser
@@ -69,6 +68,10 @@ module ROTP
69
68
  parser.on_tail('-h', '--help', 'Show this message') do
70
69
  options!.mode = :help
71
70
  end
71
+
72
+ parser.on('-d', '--digest [ALGORITHM]', 'Use algorithm for the digest (default sha1)') do |digest|
73
+ options!.digest = digest
74
+ end
72
75
  end
73
76
  end
74
77
 
@@ -83,7 +86,5 @@ module ROTP
83
86
  def red(string)
84
87
  "\033[31m#{string}\033[0m"
85
88
  end
86
-
87
89
  end
88
90
  end
89
-