mytotp 0.1.0 → 0.1.3
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 +4 -4
- data/README.md +3 -1
- data/exe/mytotp +2 -2
- data/lib/mytotp/commands/generate.rb +23 -26
- data/lib/mytotp/commands/service.rb +2 -2
- data/lib/mytotp/commands/services/add.rb +18 -15
- data/lib/mytotp/commands/services/remove.rb +18 -17
- data/lib/mytotp/commands/version.rb +2 -1
- data/lib/mytotp/commands.rb +6 -5
- data/lib/mytotp/models/service.rb +3 -0
- data/lib/mytotp/version.rb +2 -1
- data/lib/mytotp.rb +11 -9
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1709c81172ffaea43aee506997a66c17bb611fa4d6a0eca9ba363b27164a1785
|
4
|
+
data.tar.gz: f192b136f75dc6401f5878794fc763ebc28ee611aea886322c4310e049078797
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 308f62c11949e20672b4b928b46b5985cf94e143f3db63c886bfe3010419fdaef24443bf98918d53121f7c1b2203bf6bcfb6caf1e62c2208dd808eee121fc7a4
|
7
|
+
data.tar.gz: 9031ab707aa6a941048eaa8c72491b455c0fc82aa500c994f132477952d1b02d9bb91333bb6e01c8e07209fe5b2796f90ae0d6b984d7f98443c23e90f63b9957
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Mytotp
|
2
2
|
|
3
|
-
Another TOTP cli app. Nice UI, simple to use and user
|
3
|
+
Another TOTP cli app. Nice UI, simple to use and user-friendly.
|
4
|
+
|
5
|
+

|
4
6
|
|
5
7
|
## Main features
|
6
8
|
|
data/exe/mytotp
CHANGED
@@ -2,15 +2,17 @@ module Mytotp
|
|
2
2
|
module Commands
|
3
3
|
##
|
4
4
|
# Class command for generate a totp token.
|
5
|
-
# return IO
|
6
5
|
class Generate < Dry::CLI::Command
|
7
|
-
require
|
6
|
+
require 'clipboard'
|
8
7
|
|
9
|
-
desc
|
10
|
-
argument :service, require: true, desc:
|
11
|
-
argument :username, desc:
|
12
|
-
option :mode, default:
|
8
|
+
desc 'Generate a totp for a specific service.'
|
9
|
+
argument :service, require: true, desc: 'Service name.'
|
10
|
+
argument :username, desc: 'Username.'
|
11
|
+
option :mode, default: 'once', values: %w[once continuos], desc: 'The generator mode'
|
13
12
|
|
13
|
+
# call the command function
|
14
|
+
# @param service [String] Service's name to generate the totp code.
|
15
|
+
# @param username [String] Service's username to generate the totp code.
|
14
16
|
def call(service: nil, username: nil, **options)
|
15
17
|
# find services
|
16
18
|
services = Mytotp::Models::Service.where(Sequel.ilike(:service, "%#{service}%"))
|
@@ -29,12 +31,9 @@ module Mytotp
|
|
29
31
|
generate_code(service, options.fetch(:mode))
|
30
32
|
end
|
31
33
|
|
32
|
-
private
|
33
|
-
|
34
34
|
##
|
35
35
|
# Print message when is found one
|
36
|
-
#
|
37
|
-
# Returns: IO
|
36
|
+
# @param services [Collection[Mytotp::Models::Service]] Collection of services.
|
38
37
|
def found_one_message(services)
|
39
38
|
puts CLI::UI.fmt "{{green:Service:}} #{services.first.service.capitalize}"
|
40
39
|
puts CLI::UI.fmt "{{green:Username:}} #{services.first.username.capitalize}"
|
@@ -42,10 +41,10 @@ module Mytotp
|
|
42
41
|
|
43
42
|
##
|
44
43
|
# Ask which service when we have more than one found.
|
45
|
-
#
|
46
|
-
#
|
44
|
+
# @param services [Collection[Mytotp::Models::Service]] Collection of services.
|
45
|
+
# @return [Mytotp::Models::Service] selected service
|
47
46
|
def select_one(services)
|
48
|
-
CLI::UI::Prompt.ask(
|
47
|
+
CLI::UI::Prompt.ask('Which service?') do |handler|
|
49
48
|
services.each do |s|
|
50
49
|
handler.option("#{s.service} : #{s.username}") { |_selection| s }
|
51
50
|
end
|
@@ -54,11 +53,11 @@ module Mytotp
|
|
54
53
|
|
55
54
|
##
|
56
55
|
# Generate the complete message with the code
|
57
|
-
#
|
58
|
-
#
|
56
|
+
# @param service [Mytotp::Models::Service] Selected service for generate the totp code
|
57
|
+
# @param mode [String] Mode for generate the code, it can be 'continuos' or by default 'once'
|
59
58
|
def generate_code(service, mode)
|
60
59
|
totp = ROTP::TOTP.new(service.key, interval: service.period, digits: service.digits)
|
61
|
-
if mode ==
|
60
|
+
if mode == 'continuos'
|
62
61
|
# infinit loop
|
63
62
|
loop do
|
64
63
|
actual_code = totp.now
|
@@ -80,8 +79,6 @@ module Mytotp
|
|
80
79
|
|
81
80
|
##
|
82
81
|
# clear last line in the console
|
83
|
-
# Params: nil
|
84
|
-
# Returns: IO
|
85
82
|
def clear_last_line
|
86
83
|
# Clear the line
|
87
84
|
print(CLI::UI::ANSI.previous_line + CLI::UI::ANSI.clear_to_end_of_line)
|
@@ -91,24 +88,24 @@ module Mytotp
|
|
91
88
|
|
92
89
|
##
|
93
90
|
# Count seconds
|
94
|
-
#
|
95
|
-
#
|
91
|
+
# @param service [Mytotp::Models::Service] Service to validate.
|
92
|
+
# @param totp [ROTP::TOTP] totp object generated with the service token.
|
93
|
+
# @return [Integer] seconds
|
96
94
|
def valid_for(service, totp)
|
97
95
|
(service.period - (Time.now - Time.at(totp.verify(totp.now)))).round
|
98
96
|
end
|
99
97
|
|
100
98
|
##
|
101
99
|
# Print valid for
|
102
|
-
#
|
103
|
-
#
|
100
|
+
# @param service [Mytotp::Models::Service] Service to validate.
|
101
|
+
# @param totp [ROTP::TOTP] totp object generated with the service token.
|
104
102
|
def message_valid_for(service, totp)
|
105
103
|
puts CLI::UI.fmt "{{green:Valid for:}} #{valid_for(service, totp)} seconds"
|
106
104
|
end
|
107
105
|
|
108
106
|
##
|
109
107
|
# Print the code
|
110
|
-
#
|
111
|
-
# Returns: IO
|
108
|
+
# @param totp [String] totp code generate for print.
|
112
109
|
def message_code(totp)
|
113
110
|
if copy_to_clipboard(totp)
|
114
111
|
puts CLI::UI.fmt "{{green:Current TOTP:}} #{totp} - {{green:Copy!}}"
|
@@ -119,8 +116,8 @@ module Mytotp
|
|
119
116
|
|
120
117
|
##
|
121
118
|
# Copy code to clipboar
|
122
|
-
#
|
123
|
-
#
|
119
|
+
# @param code [String] Code to be copy on the clipboard.
|
120
|
+
# @return [Boolean] True or false depending if it was copy to clipboard or not.
|
124
121
|
def copy_to_clipboard(code)
|
125
122
|
Clipboard.copy(code)
|
126
123
|
Clipboard.paste == code
|
@@ -2,9 +2,9 @@ module Mytotp
|
|
2
2
|
module Commands
|
3
3
|
##
|
4
4
|
# Class command for manage services.
|
5
|
-
# return boolean.
|
6
5
|
class Service < Dry::CLI::Command
|
7
|
-
desc
|
6
|
+
desc 'Manage your services. Whitout subcommands print services.'
|
7
|
+
# call the command function
|
8
8
|
def call(*)
|
9
9
|
Mytotp::Models::Service.all.each do |s|
|
10
10
|
puts CLI::UI.fmt "{{green:#{s.service.capitalize}}} - #{s.username.downcase}"
|
@@ -1,44 +1,47 @@
|
|
1
1
|
module Mytotp
|
2
2
|
module Commands
|
3
|
+
# services subcommands module
|
4
|
+
# it's group the service subcommands
|
3
5
|
module Services
|
4
6
|
##
|
5
7
|
# Class command for add a new service.
|
6
|
-
# return String
|
7
8
|
class Add < Dry::CLI::Command
|
8
|
-
desc
|
9
|
+
desc 'Add a new service.'
|
9
10
|
|
10
|
-
argument :service, desc:
|
11
|
+
argument :service, desc: 'Service name.'
|
11
12
|
argument :username, desc: "Account's username"
|
12
|
-
argument :key, desc:
|
13
|
-
argument :digits, desc: "Length of the token"
|
14
|
-
argument :period, desc: "Duration of the token"
|
13
|
+
argument :key, desc: 'Secret key'
|
15
14
|
|
16
|
-
|
15
|
+
# execute the command
|
16
|
+
# @param service [String] service name to add
|
17
|
+
# @param username [String] username used in the service
|
18
|
+
# @param key [String] totp key shared for generate the otp codes
|
19
|
+
def call(service: nil, username: nil, key: nil, **)
|
17
20
|
service_obj = Mytotp::Models::Service.new(service: service, username: username,
|
18
|
-
key: key
|
21
|
+
key: key)
|
19
22
|
service_obj = ask_for_incomplete(service_obj)
|
20
23
|
service_obj.save
|
21
|
-
puts CLI::UI.fmt
|
24
|
+
puts CLI::UI.fmt '{{green:Correct saved!}}'
|
22
25
|
rescue StandardError => e
|
23
26
|
print(e.to_s)
|
24
|
-
puts CLI::UI.fmt
|
27
|
+
puts CLI::UI.fmt '{{red:Something is not fine, try again!}}'
|
25
28
|
end
|
26
29
|
|
27
30
|
##
|
28
31
|
# Ask incomplete information for a service_obj
|
29
|
-
#
|
30
|
-
#
|
32
|
+
# @param service_obj [Mytotp::Models::Service] the service object created with the arguments provided
|
33
|
+
# @return [Mytotp::Models::Service] the service object modify by the questions to the user
|
31
34
|
def ask_for_incomplete(service_obj)
|
32
35
|
# Check service if was input by argument or interactive ask
|
33
36
|
if service_obj.service.nil?
|
34
37
|
service_obj.service = CLI::UI.ask(
|
35
|
-
|
38
|
+
'Which service do you want to add?', allow_empty: false
|
36
39
|
)
|
37
40
|
end
|
38
41
|
# Check service if was input by argument or interactive ask
|
39
|
-
service_obj.username = CLI::UI.ask(
|
42
|
+
service_obj.username = CLI::UI.ask('Username?', allow_empty: false) if service_obj.username.nil?
|
40
43
|
# Check service if was input by argument or interactive ask
|
41
|
-
service_obj.key = CLI::UI.ask(
|
44
|
+
service_obj.key = CLI::UI.ask('Key?', allow_empty: false) if service_obj.key.nil?
|
42
45
|
service_obj
|
43
46
|
end
|
44
47
|
end
|
@@ -2,13 +2,16 @@ module Mytotp
|
|
2
2
|
module Commands
|
3
3
|
module Services
|
4
4
|
##
|
5
|
-
# Class command for
|
6
|
-
#
|
5
|
+
# Class command for remove a service.
|
6
|
+
# the service can be search by service's name and username for remove.
|
7
7
|
class Remove < Dry::CLI::Command
|
8
|
-
desc
|
9
|
-
argument :service, desc:
|
10
|
-
argument :username, desc:
|
8
|
+
desc 'Remove a service.'
|
9
|
+
argument :service, desc: 'Service name.'
|
10
|
+
argument :username, desc: 'Username.'
|
11
11
|
|
12
|
+
# Execute the command
|
13
|
+
# @param service [String] service name to remove.
|
14
|
+
# @param username [String] username in the service.
|
12
15
|
def call(service: nil, username: nil, **)
|
13
16
|
services = Mytotp::Models::Service.where(
|
14
17
|
Sequel.ilike(:service, "%#{service}%")
|
@@ -17,9 +20,9 @@ module Mytotp
|
|
17
20
|
)
|
18
21
|
case services.count
|
19
22
|
when 0
|
20
|
-
puts CLI::UI.fmt
|
23
|
+
puts CLI::UI.fmt '{{yellow:No service found}}'
|
21
24
|
when 1
|
22
|
-
CLI::UI::Frame.open(
|
25
|
+
CLI::UI::Frame.open('We found one service!') do
|
23
26
|
# ask to remove
|
24
27
|
remove(services.first.id)
|
25
28
|
end
|
@@ -31,12 +34,11 @@ module Mytotp
|
|
31
34
|
|
32
35
|
##
|
33
36
|
# Ask for which remove
|
34
|
-
#
|
35
|
-
# Returns: Nil
|
37
|
+
# @param services [Array[Mytotp::Models::Service]] Collection of services found by the input of the user.
|
36
38
|
def multiple_options(services)
|
37
|
-
CLI::UI::Frame.open(
|
39
|
+
CLI::UI::Frame.open('We found more than one!') do
|
38
40
|
# puts services.map { |s| s.service + " " + s.username }
|
39
|
-
id = CLI::UI::Prompt.ask(
|
41
|
+
id = CLI::UI::Prompt.ask('Which service do you want to remove?') do |handler|
|
40
42
|
services.each do |s|
|
41
43
|
handler.option("#{s.service} : #{s.username}") { |_selection| s.id }
|
42
44
|
end
|
@@ -47,16 +49,15 @@ module Mytotp
|
|
47
49
|
|
48
50
|
##
|
49
51
|
# Remove a service by id
|
50
|
-
#
|
51
|
-
# Returns: IO
|
52
|
+
# @param id [Integer] Unic ID of the service to remove.
|
52
53
|
def remove(id)
|
53
54
|
service_obj = Mytotp::Models::Service[id]
|
54
|
-
answer = CLI::UI.ask(
|
55
|
-
if answer ==
|
55
|
+
answer = CLI::UI.ask('Are you sure?', options: %w[yes no])
|
56
|
+
if answer == 'yes'
|
56
57
|
service_obj.delete
|
57
|
-
puts CLI::UI.fmt
|
58
|
+
puts CLI::UI.fmt '{{red:Service successfull removed!}}'
|
58
59
|
else
|
59
|
-
puts CLI::UI.fmt
|
60
|
+
puts CLI::UI.fmt '{{green:No service removed.}}'
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
data/lib/mytotp/commands.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module Mytotp
|
2
|
+
# It's include and register all commands available in the app
|
2
3
|
module Commands
|
3
4
|
extend Dry::CLI::Registry
|
4
5
|
|
5
6
|
# register clasess like commands
|
6
|
-
register
|
7
|
-
register
|
8
|
-
register
|
9
|
-
register
|
10
|
-
register
|
7
|
+
register 'version', Mytotp::Commands::Version, aliases: ['v', '-v', '--version']
|
8
|
+
register 'generate', Mytotp::Commands::Generate, aliases: ['g']
|
9
|
+
register 'service', Mytotp::Commands::Service
|
10
|
+
register 'service add', Mytotp::Commands::Services::Add
|
11
|
+
register 'service remove', Mytotp::Commands::Services::Remove
|
11
12
|
end
|
12
13
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module Mytotp
|
2
|
+
# It's include the model created for save services
|
2
3
|
module Models
|
3
4
|
##
|
4
5
|
# Service model
|
5
6
|
class Service < Sequel::Model
|
7
|
+
# callback for apply upcase to service and username,
|
8
|
+
# this is doing for make easy to search later
|
6
9
|
def before_save
|
7
10
|
self.service = service.upcase
|
8
11
|
self.username = username.upcase
|
data/lib/mytotp/version.rb
CHANGED
data/lib/mytotp.rb
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
# require_relative "mytotp/version"
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
2
|
+
require 'dry/cli'
|
3
|
+
require 'sequel'
|
4
|
+
require 'zeitwerk'
|
5
|
+
require 'cli/ui'
|
6
|
+
require 'rotp'
|
7
7
|
# code loader
|
8
8
|
Zeitwerk::Loader.eager_load_all
|
9
9
|
loader = Zeitwerk::Loader.for_gem
|
10
10
|
loader.setup # ready!
|
11
|
-
|
12
|
-
#
|
11
|
+
|
12
|
+
# Main module of the app,
|
13
|
+
# its contains the global variables and configurations
|
14
|
+
# @author a-chacon
|
13
15
|
module Mytotp
|
14
16
|
# app name
|
15
|
-
APP_NAME =
|
17
|
+
APP_NAME = 'Mytotp'.freeze
|
16
18
|
# cli configuration
|
17
19
|
CLI::UI.frame_style = :bracket
|
18
20
|
CLI::UI::StdoutRouter.enable
|
19
21
|
|
20
|
-
if ENV.fetch(
|
22
|
+
if ENV.fetch('MYTOTP_ENV', nil) == 'test'
|
21
23
|
# db connection, in memmory only
|
22
24
|
DB = Sequel.sqlite
|
23
25
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mytotp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- a-chacon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|
@@ -120,8 +120,8 @@ dependencies:
|
|
120
120
|
- - ">="
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: 2.5.4
|
123
|
-
description: Totp cli tool for who loves the cli.
|
124
|
-
|
123
|
+
description: Totp cli tool for who loves the cli. I made it for myself, I don't like
|
124
|
+
others.
|
125
125
|
email:
|
126
126
|
- andres.ch@protonmail.com
|
127
127
|
executables:
|
@@ -145,10 +145,11 @@ homepage: https://github.com/a-chacon/mytotp
|
|
145
145
|
licenses:
|
146
146
|
- GPL-3.0
|
147
147
|
metadata:
|
148
|
+
bug_tracker_uri: https://github.com/a-chacon/mytotp/issues
|
149
|
+
changelog_uri: https://github.com/a-chacon/mytotp
|
150
|
+
documentation_uri: https://www.rubydoc.info/gems/mytotp
|
148
151
|
homepage_uri: https://github.com/a-chacon/mytotp
|
149
152
|
source_code_uri: https://github.com/a-chacon/mytotp
|
150
|
-
changelog_uri: https://github.com/a-chacon/mytotp
|
151
|
-
rubygems_mfa_required: 'true'
|
152
153
|
post_install_message:
|
153
154
|
rdoc_options: []
|
154
155
|
require_paths:
|
@@ -167,5 +168,5 @@ requirements: []
|
|
167
168
|
rubygems_version: 3.2.22
|
168
169
|
signing_key:
|
169
170
|
specification_version: 4
|
170
|
-
summary: Another totp cli
|
171
|
+
summary: Another boring totp cli.
|
171
172
|
test_files: []
|