ttoken 0.1.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/.gitignore +9 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +23 -0
- data/README.md +52 -0
- data/bin/ttoken +14 -0
- data/config/ttoken.yml.example +8 -0
- data/lib/ttoken.rb +54 -0
- data/lib/ttoken/config.rb +34 -0
- data/lib/ttoken/encrypt.rb +44 -0
- data/lib/ttoken/store.rb +44 -0
- data/lib/ttoken/version.rb +3 -0
- data/ttoken.gemspec +23 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f57d2d3a74e0441e24f73e7776033882771c2710d8e57979e78d7ccd859f903e
|
4
|
+
data.tar.gz: 604f0afb5e97d18bf223d41dc764bd94597ab23c46d89eacb59b1b4793696fcb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b4999a535b8fc61cc4cf3749c1099b46a7c73a8fe18cec75ab6a28c7e618a640e03860fb39c5b389bccb26d3eff39cec1fe7f676d58e73cdb0f81d938e2736b
|
7
|
+
data.tar.gz: 22581b23450161e2db3fbbb6d83cfaa81b63aef06ee1ec958540f0ce7200e193cb62fd00af24318efc020bf2bdac4db6d260a5a731f2fe1b1d300e12a5e5346c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
fileutils (1.4.1)
|
7
|
+
openssl (2.2.0)
|
8
|
+
public_suffix (4.0.5)
|
9
|
+
rotp (6.0.0)
|
10
|
+
addressable (~> 2.7)
|
11
|
+
yaml (0.1.0)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
fileutils
|
18
|
+
openssl
|
19
|
+
rotp
|
20
|
+
yaml
|
21
|
+
|
22
|
+
BUNDLED WITH
|
23
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Ttoken
|
2
|
+
|
3
|
+
Ttoken is a command-line program to generate time-based token/OTP.
|
4
|
+
|
5
|
+
Apart from generating time-based OTP, it provides the feature of creating pin+token and copies it to the clipboard so that user can enter it anywhere by just the click of Ctrl+v.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# yum install ruby rubygems
|
11
|
+
|
12
|
+
# gem install ttoken
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Gem provides the executable command-line program - ttoken.
|
18
|
+
|
19
|
+
1) To encrypt and save your password/pin in ttoken use the below command.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# ttoken --encrypt
|
23
|
+
```
|
24
|
+
|
25
|
+
2) Create the file `/etc/ttoken/ttoken.yml` and enter the below content.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# Issuer - The site or app you are creating the OTP
|
29
|
+
:issuer: 'Red Hat'
|
30
|
+
|
31
|
+
# Time-based token provided by issuer
|
32
|
+
:token: "1234abcdxyz"
|
33
|
+
|
34
|
+
# Enable pin+token
|
35
|
+
:pinplustoken: yes
|
36
|
+
|
37
|
+
```
|
38
|
+
Make sure you change the issuer and token.
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
3) Running the command will generate pin+token and will copy it to the clipboard.
|
43
|
+
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# ttoken
|
47
|
+
```
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/patilsuraj767/ttoken.
|
52
|
+
|
data/bin/ttoken
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
4
|
+
|
5
|
+
require 'ttoken'
|
6
|
+
|
7
|
+
CONFIG_FILE = '/etc/ttoken/ttoken.yml'.freeze
|
8
|
+
ENCRYPTION_KEY_FILE = File.expand_path('~/.ttoken/ttoken_encryption_key.yml')
|
9
|
+
|
10
|
+
Ttoken.setup
|
11
|
+
Ttoken.run
|
12
|
+
|
13
|
+
|
14
|
+
|
data/lib/ttoken.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require "ttoken/version"
|
2
|
+
require 'rotp'
|
3
|
+
require 'clipboard'
|
4
|
+
require 'io/console'
|
5
|
+
|
6
|
+
module Ttoken
|
7
|
+
require 'ttoken/config'
|
8
|
+
require 'ttoken/encrypt'
|
9
|
+
require 'ttoken/store'
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :config
|
13
|
+
|
14
|
+
def setup
|
15
|
+
self.config = Config.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
encrypt = Encrypt.new
|
20
|
+
if ARGV.length > 0 && ARGV[0] == '--encrypt'
|
21
|
+
pin = STDIN.getpass("Password/Pin:")
|
22
|
+
encrypted_pin = encrypt.encrypt_pin(pin)
|
23
|
+
Store.save_password(encrypted_pin)
|
24
|
+
else
|
25
|
+
token = generate_token(config.token, config.issuer)
|
26
|
+
if config.pinplustoken
|
27
|
+
password = Store.retrive_password
|
28
|
+
decrypted_pin = encrypt.decrypt_pin(password)
|
29
|
+
send_to_clipboard(decrypted_pin + token)
|
30
|
+
else
|
31
|
+
send_to_clipboard(token)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_token(token, issuer)
|
37
|
+
begin
|
38
|
+
ROTP::TOTP.new(token, issuer: issuer).now
|
39
|
+
rescue StandardError => e
|
40
|
+
raise " \nSomething went wrong. Please check if all parameters in /etc/ttoken/ttoken.yml are correct.\n Error: #{e.message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_to_clipboard(text)
|
45
|
+
begin
|
46
|
+
system("echo -n #{text} | xclip -selection clipboard")
|
47
|
+
puts 'Data copied to clipboard. Ready to paste.'
|
48
|
+
rescue StandardError => e
|
49
|
+
raise "Problem in copying data to clipboard. Error: #{e.message}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
module Ttoken
|
3
|
+
class Config
|
4
|
+
attr_accessor :config_file, :token, :issuer, :pinplustoken
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@config_file = config_file_path
|
8
|
+
@options = load_config
|
9
|
+
@token = @options.fetch(:token, nil)
|
10
|
+
@issuer = @options.fetch(:issuer, nil)
|
11
|
+
@pinplustoken = @options.fetch(:pinplustoken, false)
|
12
|
+
end
|
13
|
+
|
14
|
+
def config_file_path
|
15
|
+
File.exist?(CONFIG_FILE) ? CONFIG_FILE : File.join(source_path, 'config/ttoken.yml')
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_config
|
19
|
+
if File.exist?(config_file)
|
20
|
+
YAML.load(File.open(config_file)) || {}
|
21
|
+
else
|
22
|
+
puts "Config file #{config_file} not found, using default configuration"
|
23
|
+
{}
|
24
|
+
end
|
25
|
+
rescue StandardError => e
|
26
|
+
raise "Couldn't load configuration file. Error: #{e.message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def source_path
|
30
|
+
File.expand_path('../../..', __FILE__)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
class Encrypt
|
3
|
+
CIPHER = OpenSSL::Cipher.new('aes-256-cbc')
|
4
|
+
|
5
|
+
def encrypt_pin(pin)
|
6
|
+
if is_encryptable?(pin)
|
7
|
+
cipher = CIPHER.encrypt
|
8
|
+
cipher.key = encryption_key
|
9
|
+
s = cipher.update(pin) + cipher.final
|
10
|
+
s.unpack('H*')[0].upcase
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt_pin(pin)
|
15
|
+
if is_decryptable?(pin)
|
16
|
+
cipher = CIPHER.decrypt
|
17
|
+
cipher.key = encryption_key
|
18
|
+
s = [pin].pack("H*").unpack("C*").pack("c*")
|
19
|
+
begin
|
20
|
+
cipher.update(s) + cipher.final
|
21
|
+
rescue StandardError => e
|
22
|
+
raise "\n Problem in decrypting password. To resolve the issue encrypt and save the password again using command # ttoken --encrypt. \n Error: #{e.message}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_encryptable?(str)
|
28
|
+
!encryption_key.nil? && !str.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def is_decryptable?(str)
|
32
|
+
!encryption_key.nil? && !str.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def encryption_key
|
36
|
+
if File.exist?(ENCRYPTION_KEY_FILE)
|
37
|
+
Store.retrive_encryption_key
|
38
|
+
else
|
39
|
+
key = CIPHER.random_key
|
40
|
+
Store.save_encryption_key(key)
|
41
|
+
key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/ttoken/store.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
class Store
|
3
|
+
PASSWORD_FILE = File.expand_path('~/.ttoken/ttoken.yml')
|
4
|
+
|
5
|
+
def self.save_password(password)
|
6
|
+
create_dir
|
7
|
+
data = {password: password}
|
8
|
+
begin
|
9
|
+
File.write(PASSWORD_FILE, data.to_yaml)
|
10
|
+
puts 'Password saved successfully. Use command #ttoken to generate pin+token'
|
11
|
+
rescue StandardError => e
|
12
|
+
raise "Unable to write password file. Error: #{e.message}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.retrive_password
|
17
|
+
if File.exist?(PASSWORD_FILE)
|
18
|
+
pf = YAML.load(File.read(PASSWORD_FILE))
|
19
|
+
pf[:password]
|
20
|
+
else
|
21
|
+
puts 'Password file does not exits. Save the password/pin using command # ttoken --encrypt'
|
22
|
+
exit 2
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.retrive_encryption_key
|
27
|
+
if File.exist?(ENCRYPTION_KEY_FILE)
|
28
|
+
pf = YAML.load(File.read(ENCRYPTION_KEY_FILE))
|
29
|
+
pf[:encryption_key]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.save_encryption_key(encryption_key)
|
34
|
+
create_dir
|
35
|
+
data = {encryption_key: encryption_key}
|
36
|
+
File.write(ENCRYPTION_KEY_FILE, data.to_yaml)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.create_dir
|
40
|
+
dir = File.expand_path('~/.ttoken')
|
41
|
+
Dir.mkdir(dir) unless Dir.exist?(dir)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/ttoken.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'lib/ttoken/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "ttoken"
|
5
|
+
spec.version = Ttoken::VERSION
|
6
|
+
spec.authors = ["Suraj Patil"]
|
7
|
+
spec.email = ["patilsuraj767@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{ttoken is a command line utility to generate time based token/otp.}
|
10
|
+
spec.homepage = "https://github.com/patilsuraj767/ttoken"
|
11
|
+
|
12
|
+
# Specify which files should be added to the gem when it is released.
|
13
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
14
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
15
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|images)/}) }
|
16
|
+
end
|
17
|
+
|
18
|
+
spec.executables = ['ttoken']
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'rotp', '5.1.0'
|
22
|
+
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ttoken
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Suraj Patil
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rotp
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.0
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- patilsuraj767@gmail.com
|
30
|
+
executables:
|
31
|
+
- ttoken
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- Gemfile
|
37
|
+
- Gemfile.lock
|
38
|
+
- README.md
|
39
|
+
- bin/ttoken
|
40
|
+
- config/ttoken.yml.example
|
41
|
+
- lib/ttoken.rb
|
42
|
+
- lib/ttoken/config.rb
|
43
|
+
- lib/ttoken/encrypt.rb
|
44
|
+
- lib/ttoken/store.rb
|
45
|
+
- lib/ttoken/version.rb
|
46
|
+
- ttoken.gemspec
|
47
|
+
homepage: https://github.com/patilsuraj767/ttoken
|
48
|
+
licenses: []
|
49
|
+
metadata: {}
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 2.7.6.2
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: ttoken is a command line utility to generate time based token/otp.
|
70
|
+
test_files: []
|