onetime-totp 1.0.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.
- checksums.yaml +7 -0
- data/lib/onetime.rb +130 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dc3fd60991cff4658e421a6ae1c94d8976f8473442c7d1e480f242647cc2639f
|
4
|
+
data.tar.gz: 41467f12ee65a75c97e2ba5074f1d3fd8708a1c36a640a27f84a9fc1e1c97079
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f8e414491afa3ba4b0183ddc6b3e981aa6b2cbc73db1ee2b7a694033596be35d8a97c47e348ac2efd923ea2a6da8478ba9fec9057aeb65929c33372c5e8bbed
|
7
|
+
data.tar.gz: 9569c0a21c52a6b9618805bcc8a9326c9f3e0ae9a90c0f34ad04c83283b56607042cbb9fa7ce80af669acfaacf5b35d8c23355df3c41a0687af33a4a76d38c79
|
data/lib/onetime.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
################################################################################
|
2
|
+
# #
|
3
|
+
# OneTime password generator - 2020 fboccacini@gmail.com <Fabio Boccacini> #
|
4
|
+
# v1.0 #
|
5
|
+
# #
|
6
|
+
################################################################################
|
7
|
+
|
8
|
+
require 'openssl'
|
9
|
+
require 'base64'
|
10
|
+
require 'base32'
|
11
|
+
require 'json'
|
12
|
+
require 'net/https'
|
13
|
+
|
14
|
+
class OneTime
|
15
|
+
|
16
|
+
attr_accessor :step, :encryption, :length
|
17
|
+
attr_reader :password, :secret, :generation_time
|
18
|
+
|
19
|
+
def initialize(secret, length: 6, step: 30, encryption: 'SHA512')
|
20
|
+
|
21
|
+
@secret = secret
|
22
|
+
@length = length
|
23
|
+
@step = step
|
24
|
+
@encryption = encryption
|
25
|
+
self.generate
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate(time: Time.now,
|
30
|
+
length: self.length,
|
31
|
+
step: self.step,
|
32
|
+
encryption: self.encryption,
|
33
|
+
reset: false)
|
34
|
+
|
35
|
+
begin
|
36
|
+
|
37
|
+
# If reset is true nil the generation time
|
38
|
+
@generation_time = time.clone if reset == true || @generation_time.nil?
|
39
|
+
|
40
|
+
# Binary key from time / step
|
41
|
+
rounded_step = (time.to_f - @generation_time.to_f).floor / step
|
42
|
+
key = ['%0.16x' % (rounded_step).to_s(16).hex].pack('H*')
|
43
|
+
|
44
|
+
# Convert secret's non base32 char to base32 and back to string
|
45
|
+
data = Base32.decode(Base32.encode(self.secret))
|
46
|
+
|
47
|
+
# Get initial HMAC hash
|
48
|
+
hash = OpenSSL::HMAC.digest(encryption.downcase, data, key)
|
49
|
+
|
50
|
+
# Dynamic truncation:
|
51
|
+
# Get the last for bit of the last byte of the hash
|
52
|
+
offset = hash[hash.length - 1].ord & 0xf
|
53
|
+
|
54
|
+
# Get the for bytes pointed by the offset
|
55
|
+
hash = hash[offset .. offset + 3].bytes
|
56
|
+
|
57
|
+
# Get new hash
|
58
|
+
truncated_hash = ((hash[0] & 0x7f) << 24) |
|
59
|
+
((hash[1] & 0xff) << 16) |
|
60
|
+
((hash[2] & 0xff) << 8) |
|
61
|
+
(hash[3] & 0xff)
|
62
|
+
|
63
|
+
# Get actual password
|
64
|
+
@password = "%0.#{length}d" % (truncated_hash % (10 ** length));
|
65
|
+
|
66
|
+
return self.password
|
67
|
+
|
68
|
+
rescue Exception => e
|
69
|
+
puts e.message
|
70
|
+
# puts e.backtrace.join("\n")
|
71
|
+
return nil
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def verify(password, time: Time.now,
|
77
|
+
length: self.length,
|
78
|
+
step: self.step,
|
79
|
+
encryption: self.encryption)
|
80
|
+
|
81
|
+
# verify a password correctness for a given time
|
82
|
+
begin
|
83
|
+
|
84
|
+
return self.generate(time: time,
|
85
|
+
length: length,
|
86
|
+
step: step,
|
87
|
+
encryption: encryption) == password
|
88
|
+
|
89
|
+
rescue Exception => e
|
90
|
+
puts e.message
|
91
|
+
# puts e.backtrace.join("\n")
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
def call_service(url, user, payload, content_type: 'application/json', accept: '*/*')
|
98
|
+
|
99
|
+
begin
|
100
|
+
|
101
|
+
self.generate if self.password.nil?
|
102
|
+
|
103
|
+
# Base64 encode authentication for the header
|
104
|
+
auth = Base64.strict_encode64("#{user}:#{self.password}".encode("ASCII"))
|
105
|
+
|
106
|
+
# Prep uri and headers
|
107
|
+
uri = URI.parse(url)
|
108
|
+
headers = {
|
109
|
+
'Authorization' => "Basic #{auth}",
|
110
|
+
'Content-Type' => content_type,
|
111
|
+
'Accept' => accept
|
112
|
+
}
|
113
|
+
|
114
|
+
# Create request
|
115
|
+
request = Net::HTTP.new(uri.host, uri.port)
|
116
|
+
request.use_ssl = true
|
117
|
+
|
118
|
+
# Send request
|
119
|
+
return request.post(uri.path, payload.to_json, headers)
|
120
|
+
rescue Exception => e
|
121
|
+
puts e.message
|
122
|
+
# puts e.backtrace.join("\n")
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: onetime-totp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fabio Boccacini
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: base32
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.3'
|
27
|
+
description: |-
|
28
|
+
A TOTP generator, that includes validation, generation and send methods.
|
29
|
+
See https://github.com/fboccacini/onetime-totp for reference and usage.
|
30
|
+
email: fboccacini@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- lib/onetime.rb
|
36
|
+
homepage: https://github.com/fboccacini/onetime-totp
|
37
|
+
licenses:
|
38
|
+
- MIT
|
39
|
+
metadata: {}
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.0.3
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Time-based One Time Password (TOTP) generator.
|
59
|
+
test_files: []
|