mfa 0.0.1
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/Gemfile +6 -0
- data/Onafile +254 -0
- data/bin/mfa +4 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: abc69612ca114cbc9b3735453b8602485cc4f95d8dd5d71ae2f4eb10c3cdc335
|
4
|
+
data.tar.gz: b6d3146f3318d006190f2f813b44533519203641b1bdf6b1d790c725f818156f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 766faa173d7b177cbc932638cbcb87fc51cb204a6b6583789afe701abfed32e5420c226896c52d31f067a1d541fc7147c6a7707976ebc776b570b512440bc032
|
7
|
+
data.tar.gz: f9d668031f3e571e961be1283e49ded04eb259955c30cbaecd1c540a6d6eea4456dc50597e907a605c41b586a6162cb26fc93633735db96c373563de4c12618e
|
data/Gemfile
ADDED
data/Onafile
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'abstract_command'
|
4
|
+
require 'isna'
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module Command
|
9
|
+
class GetMfa < AbstractCommand
|
10
|
+
def template
|
11
|
+
'security find-generic-password -w -a %<account>s -s %<service>s %<keychain>s'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class SetMfa < AbstractCommand
|
15
|
+
def template
|
16
|
+
'security add-generic-password -a %<account>s -s %<service>s -w %<mfa>s %<keychain>s'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class RmMfa < AbstractCommand
|
20
|
+
def template
|
21
|
+
'security delete-generic-password -a %<account>s -s %<service>s %<keychain>s'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
class CreateKeychain < AbstractCommand
|
25
|
+
def template
|
26
|
+
'security create-keychain %<keychain>s'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
class DeleteKeychain < AbstractCommand
|
30
|
+
def template
|
31
|
+
'security delete-keychain %<keychain>s'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
class ListMfa < AbstractCommand
|
35
|
+
def template
|
36
|
+
"security dump-keychain %<keychain>s | awk -F'=' '/0x00000007/ { print $2 }'"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
class ResolveMfa < AbstractCommand
|
40
|
+
def template
|
41
|
+
'oathtool -b --totp %<seed>s'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
KEYCHAIN = 'mfa'
|
47
|
+
|
48
|
+
Ona.prompt = 'Mfa'
|
49
|
+
|
50
|
+
Ona.resource(:mfa, [:service])
|
51
|
+
|
52
|
+
def load_mfa_list
|
53
|
+
Command::ListMfa.new(:keychain => KEYCHAIN).backtick.each_line do |line|
|
54
|
+
line.chomp!
|
55
|
+
next if line == ''
|
56
|
+
Ona.register(:mfa) do |mfa|
|
57
|
+
mfa.service = line.gsub(/^"|"$/, '')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def unload_mfa_list
|
63
|
+
Ona.class_eval do
|
64
|
+
puts @resources[:mfa][:entries] = []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def reset_mfa_list
|
69
|
+
unload_mfa_list
|
70
|
+
load_mfa_list
|
71
|
+
end
|
72
|
+
|
73
|
+
load_mfa_list
|
74
|
+
|
75
|
+
def print_command(command)
|
76
|
+
puts ''
|
77
|
+
puts "# Command: #{command.to_ansi.yellow.to_s}"
|
78
|
+
puts "# Executed at: #{Time.now.to_s}"
|
79
|
+
puts "# #{('=' * 76).to_ansi.cyan.to_s}"
|
80
|
+
puts ''
|
81
|
+
end
|
82
|
+
|
83
|
+
Ona.action(
|
84
|
+
:regex => /^create-keychain$/,
|
85
|
+
:resource => :mfa,
|
86
|
+
:text => 'Create the MFA Keychain.',
|
87
|
+
:example => 'create-keychain'
|
88
|
+
) do |mfa, input, regex|
|
89
|
+
command = Command::CreateKeychain.new
|
90
|
+
command.keychain = KEYCHAIN
|
91
|
+
print_command command.to_s
|
92
|
+
command.system
|
93
|
+
end
|
94
|
+
|
95
|
+
Ona.action(
|
96
|
+
:regex => /^delete-keychain$/,
|
97
|
+
:resource => :mfa,
|
98
|
+
:text => 'Delete the MFA Keychain.',
|
99
|
+
:example => 'delete-keychain'
|
100
|
+
) do |mfa, input, regex|
|
101
|
+
command = Command::DeleteKeychain.new
|
102
|
+
command.keychain = KEYCHAIN
|
103
|
+
print_command command.to_s
|
104
|
+
command.system
|
105
|
+
reset_mfa_list
|
106
|
+
end
|
107
|
+
|
108
|
+
Ona.action(
|
109
|
+
:regex => /(^)(set)(\s)([^ ]+)(\s)(.*)($)/,
|
110
|
+
:resource => :mfa,
|
111
|
+
:text => 'Add a new MFA entry.',
|
112
|
+
:example => 'set [SERVICE] [MFA]',
|
113
|
+
) do |mfa, input, regex|
|
114
|
+
command = Command::SetMfa.new
|
115
|
+
command.account = KEYCHAIN
|
116
|
+
command.service = input.scan(regex)[0][3]
|
117
|
+
command.keychain = KEYCHAIN
|
118
|
+
command.mfa = input.scan(regex)[0][5]
|
119
|
+
print_command command.to_s
|
120
|
+
command.system
|
121
|
+
reset_mfa_list
|
122
|
+
end
|
123
|
+
|
124
|
+
Ona.action(
|
125
|
+
:regex => /(^)(get)(\s)(\d+)($)/,
|
126
|
+
:resource => :mfa,
|
127
|
+
:text => 'Get mfa from keychain and send to clipboard.',
|
128
|
+
:example => 'get [NUMBER]',
|
129
|
+
:find => true,
|
130
|
+
:token => proc { |scan| scan[0][3] }
|
131
|
+
) do |mfa, id|
|
132
|
+
command = Command::GetMfa.new
|
133
|
+
command.account = KEYCHAIN
|
134
|
+
command.service = mfa.service
|
135
|
+
command.keychain = KEYCHAIN
|
136
|
+
seed = command.backtick.chomp
|
137
|
+
puts " #{id.to_s.to_ansi.cyan.to_s} - #{'service'.to_ansi.green.to_s} : #{mfa.service}"
|
138
|
+
command = Command::ResolveMfa.new(:seed => seed)
|
139
|
+
secret = command.backtick.chomp
|
140
|
+
puts " * Sent to clipboard!".to_ansi.yellow.to_s
|
141
|
+
puts " > ".to_ansi.cyan.blink.to_s + "#{secret}"
|
142
|
+
Dir.mktmpdir do |dir|
|
143
|
+
fname = "#{dir}/file.txt"
|
144
|
+
File.open(fname, 'w+') do |file|
|
145
|
+
file.print secret.chomp
|
146
|
+
end
|
147
|
+
system "cat #{fname} | pbcopy"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
Ona.action(
|
152
|
+
:regex => /(^)(dump)(\s)(\d+)($)/,
|
153
|
+
:resource => :mfa,
|
154
|
+
:text => 'Dump seed, service, and code to STDOUT.',
|
155
|
+
:example => 'dump [NUMBER]',
|
156
|
+
:find => true,
|
157
|
+
:token => proc { |scan| scan[0][3] }
|
158
|
+
) do |mfa, id|
|
159
|
+
command = Command::GetMfa.new
|
160
|
+
command.account = KEYCHAIN
|
161
|
+
command.service = mfa.service
|
162
|
+
command.keychain = KEYCHAIN
|
163
|
+
puts " #{id.to_s.to_ansi.cyan.to_s} - #{'service'.to_ansi.green.to_s} : #{mfa.service}"
|
164
|
+
puts " - mfa : #{command.backtick.chomp}"
|
165
|
+
end
|
166
|
+
|
167
|
+
Ona.action(
|
168
|
+
:regex => /(^)(rm)(\s)(\d+)($)/,
|
169
|
+
:resource => :mfa,
|
170
|
+
:text => 'Remove an existing mfa seed.',
|
171
|
+
:example => 'rm [NUMBER]',
|
172
|
+
:find => true,
|
173
|
+
:token => proc { |scan| scan[0][3] }
|
174
|
+
) do |mfa, id|
|
175
|
+
command = Command::RmMfa.new
|
176
|
+
command.account = KEYCHAIN
|
177
|
+
command.service = mfa.service
|
178
|
+
command.keychain = KEYCHAIN
|
179
|
+
print_command command.to_s
|
180
|
+
command.system
|
181
|
+
end
|
182
|
+
|
183
|
+
Ona.action(
|
184
|
+
:regex => /(^)(ls)($)/,
|
185
|
+
:resource => :mfa,
|
186
|
+
:text => 'List all MFAs.',
|
187
|
+
:example => 'ls',
|
188
|
+
) do |mfa, id|
|
189
|
+
mfa.each_with_index do |mfa, id|
|
190
|
+
puts " #{id.to_s.to_ansi.cyan.to_s} - #{'service'.to_ansi.green.to_s} : #{mfa.service}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
Ona.action(
|
195
|
+
:regex => /(^)(export)($)/,
|
196
|
+
:resource => :mfa,
|
197
|
+
:text => 'Export all MFAs.',
|
198
|
+
:example => 'export',
|
199
|
+
) do |mfa, id|
|
200
|
+
mfa.each_with_index do |mfa, id|
|
201
|
+
command = Command::GetMfa.new
|
202
|
+
command.account = KEYCHAIN
|
203
|
+
command.service = mfa.service
|
204
|
+
command.keychain = KEYCHAIN
|
205
|
+
seed = command.backtick.chomp
|
206
|
+
object = {
|
207
|
+
:service => mfa.service,
|
208
|
+
:seed => seed
|
209
|
+
}
|
210
|
+
puts object.to_json
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
Ona.action(
|
215
|
+
:regex => /(^)(import)(\s)(.*\.json)($)/,
|
216
|
+
:resource => :mfa,
|
217
|
+
:text => 'Import MFAs from a json file.',
|
218
|
+
:example => 'import [FILE]',
|
219
|
+
) do |mfa, command, regex|
|
220
|
+
file = regex.match(command)[4]
|
221
|
+
puts "Importing from #{file}"
|
222
|
+
unless File.exists?(file)
|
223
|
+
puts "File #{file} does not exist."
|
224
|
+
next
|
225
|
+
end
|
226
|
+
File.read(file).each_line do |line|
|
227
|
+
object = JSON.parse(line)
|
228
|
+
Ona.run("set #{object['service']} #{object['seed']}")
|
229
|
+
end
|
230
|
+
reset_mfa_list
|
231
|
+
puts "Import has completed."
|
232
|
+
end
|
233
|
+
|
234
|
+
Ona.action(
|
235
|
+
:regex => /(^)(s)(\s)(.*)($)/,
|
236
|
+
:resource => :mfa,
|
237
|
+
:text => 'Search by service.',
|
238
|
+
:example => 's [STRING]'
|
239
|
+
) do |mfa, command, regex|
|
240
|
+
text = command.scan(regex)[0][3]
|
241
|
+
r = Regexp.new(text)
|
242
|
+
mfa.each_with_index do |mfa, id|
|
243
|
+
next unless r.match(mfa.to_s)
|
244
|
+
match = " #{id.to_s.to_ansi.cyan.to_s} - #{'service'.to_ansi.green.to_s} : #{mfa.service}"
|
245
|
+
puts match.gsub(text, text.to_ansi.red.to_s)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
if ARGV.size > 0
|
250
|
+
Ona.defaults
|
251
|
+
Ona.run(ARGV.join(' '))
|
252
|
+
exit 0
|
253
|
+
end
|
254
|
+
|
data/bin/mfa
ADDED
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mfa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kazuyoshi Tlacaelel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-07-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: isna
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: abstract_command
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.0.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ona
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
description:
|
56
|
+
email: kazu.dev@gmail.com
|
57
|
+
executables:
|
58
|
+
- mfa
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- Gemfile
|
63
|
+
- Onafile
|
64
|
+
- bin/mfa
|
65
|
+
homepage: https://github.com/ktlacaelel/mfa
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubygems_version: 3.3.7
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: mfa - mfa utility tool
|
88
|
+
test_files: []
|