acm 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b36ad4f4d58f49342edd31fad00cd4d69c2dcde572a141dce2954068c88440a
4
- data.tar.gz: dfe7d646e1d8e2aae1c7af64d3fa8d68a19eed3a2c7bb7c3895e51e041a73ba8
3
+ metadata.gz: b8a6ae6c1c5af67e6343fd6c25e0cddbd9d1d2038f57d961e7c681d7edf7ffda
4
+ data.tar.gz: 2144945bb16411304ee5018d56410f07c7fdde7c0ce5ba406fd07b2cee1f451e
5
5
  SHA512:
6
- metadata.gz: 51e8e91d68d9e9ba06aece546f37ec08fe45fc1606a5bc2355e70641e9286c94b98f146d5ebe7ae6454434f23e043e8a64065c821808f4430672a8ceccfc8741
7
- data.tar.gz: 540d94db6e7c8e2eb0cbbc57450d0efc5a697aab1bf7e9a73662af175f12f7427d03208c1943e96f6ccd0ca8f273e445a679db54ea55c5885c57d8e60ca72165
6
+ metadata.gz: b4bcf239d333fc8beaca52ff8091fae3461b4b2c1b43e1d9fba96ecca20cb2d553a40299a0055a8c0a184753e223ef933a1a0c3efe5acad138df8bc019090784
7
+ data.tar.gz: ed121534dc47e3ce0e4b918841687e57b33ca5e3d5e4d16056fce3f9ec6fe452d46844704f461d458c97e0a8944f61bae5ca06612bbcf9e5d844cc0e014045dc
data/.gitignore CHANGED
@@ -1,10 +1,11 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- .ruby-version
1
+ /.bundle/
2
+ /vendor/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ .ruby-version
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
- language: ruby
2
- rvm:
3
- - 2.1.7
4
- before_install: gem install bundler -v 1.10.6
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.7
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in acm.gemspec
4
- gemspec
5
-
6
- gem "ffi", :platforms => [:mswin, :mingw, :x64_mingw]
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acm.gemspec
4
+ gemspec
5
+
6
+ gem "ffi", :platforms => [:mswin, :mingw, :x64_mingw]
data/LICENSE.txt CHANGED
@@ -1,22 +1,22 @@
1
- Copyright (c) 2015-2020 takatoh
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2015-2020 takatoh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,108 +1,129 @@
1
- # acm
2
-
3
- A simple account manager. This is NOT secure, excuse me ;p.
4
-
5
-
6
- ## Installation
7
-
8
- Install it yourself as:
9
-
10
- > gem install acm
11
-
12
- If you are using Windows, please install ffi gem:
13
-
14
- > gem install ffi
15
-
16
- ## Usage
17
-
18
- At first, init database:
19
-
20
- > acm init
21
-
22
- The database file is saved as "ENV['ACMDB']" or "ENV['HOME']/.accounts", in YAML.
23
- Set location of database file to environment variable 'ACMDB', if you want.
24
-
25
- Add account:
26
-
27
- > acm add takatoh.m@gmail.com
28
- (acm) Key? email
29
- (acm) Value? takatoh.m@gmail.com
30
- (acm) Key? password
31
- (acm) Value? xxxxxxxx
32
- (acm) Key? # Enter to exit.
33
-
34
- Then added account to database.
35
-
36
- List account(s):
37
-
38
- > acm list
39
- takatoh.m@gmail.com
40
-
41
- Search account(s):
42
-
43
- > acm search gmail
44
- takatoh.m@gmail.com
45
-
46
- Show details:
47
-
48
- > acm show takatoh.m@gmail.com
49
- Account: takatoh.m@gmail.com
50
- email: takatoh.m@gmail.com
51
- password: ******
52
-
53
- In default, value of password is masked. If you see the password, give --pass option.
54
- Or --clip option copies the password to clipboard.
55
-
56
- Update value of key:
57
-
58
- > acm update takatoh.m@gmail.com password yyyyyyyy
59
-
60
- > acm show --pass takatoh.m@gmail.com
61
- Account: takatoh.m@gmail.com
62
- email: takatoh.m@gmail.com
63
- password: yyyyyyyy
64
-
65
- Remove key and value:
66
-
67
- > acm remove-key takatoh.m@gmail.com password
68
-
69
- > acm show takatoh.m@gmail.com
70
- Account: takatoh.m@gmail.com
71
- email: takatoh.m@gmail.com
72
-
73
- Rename account:
74
-
75
- > acm rename-account takatoh.m@gmail.com Gmail
76
-
77
- > acm show Gmail
78
- Account: Gmail
79
- email: takatoh.m@gmail.com
80
-
81
- And remove account:
82
-
83
- > acm remove-account Gmail
84
- Account: Gmail
85
- email: takatoh.m@gmail.com
86
-
87
- Are you sure?(y/n) y # Enter 'y' to remove.
88
-
89
- > acm show Gmail
90
- No such account: Gmail
91
-
92
-
93
- ## Special key: login-with
94
-
95
- Special key 'login-with' is reference to other account.
96
-
97
- > acm add SomeWebService
98
- (acm) Key? login-with
99
- (acm) Value? GitHub
100
- (acm) Key? # Enter to exit.
101
-
102
- To track reference, use acm show command with --track option.
103
-
104
- > acm show --track SomeWebService
105
-
106
- ## License
107
-
108
- MIT License
1
+ # acm
2
+
3
+ A simple account manager. This is NOT secure, excuse me ;p.
4
+
5
+
6
+ ## Installation
7
+
8
+ Install it yourself as:
9
+
10
+ > gem install acm
11
+
12
+ If you are using Windows, please install ffi gem:
13
+
14
+ > gem install ffi
15
+
16
+ ## Usage
17
+
18
+ At first, init database:
19
+
20
+ > acm init
21
+
22
+ The database file is saved as "ENV['ACMDB']" or "ENV['HOME']/.accounts", in YAML.
23
+ Set location of database file to environment variable 'ACMDB', if you need.
24
+
25
+ Add account:
26
+
27
+ > acm add takatoh.m@gmail.com
28
+ (acm) Key? email
29
+ (acm) Value? takatoh.m@gmail.com
30
+ (acm) Key? password
31
+ (acm) Value? xxxxxxxx
32
+ (acm) Key? # Enter to exit.
33
+
34
+ Then added account to database.
35
+
36
+ List account(s):
37
+
38
+ > acm list
39
+ takatoh.m@gmail.com
40
+
41
+ Search account(s):
42
+
43
+ > acm search gmail
44
+ takatoh.m@gmail.com
45
+
46
+ Show details:
47
+
48
+ > acm show takatoh.m@gmail.com
49
+ Account: takatoh.m@gmail.com
50
+ email: takatoh.m@gmail.com
51
+ password: ******
52
+
53
+ In default, value of `password` is masked. If you need to see the password, give `--pass` option.
54
+ Or `--clip` option copies the password to clipboard.
55
+
56
+ Update value of key:
57
+
58
+ > acm update takatoh.m@gmail.com password yyyyyyyy
59
+
60
+ > acm show --pass takatoh.m@gmail.com
61
+ Account: takatoh.m@gmail.com
62
+ email: takatoh.m@gmail.com
63
+ password: yyyyyyyy
64
+
65
+ Remove key and value:
66
+
67
+ > acm remove-key takatoh.m@gmail.com password
68
+
69
+ > acm show takatoh.m@gmail.com
70
+ Account: takatoh.m@gmail.com
71
+ email: takatoh.m@gmail.com
72
+
73
+ Create alias for account:
74
+
75
+ > acm alias google takatoh.m@gmail.com
76
+ Create alias: google for takatoh.m@gmail.com
77
+
78
+ > acm show google
79
+ NOTE: 'google' is alias for 'takatoh.m@gmail.com'.
80
+ Account: takatoh.m@gmail.com
81
+ email: takatoh.m@gmail.com
82
+
83
+ Rename account:
84
+
85
+ > acm rename-account takatoh.m@gmail.com Gmail
86
+
87
+ > acm show Gmail
88
+ Account: Gmail
89
+ email: takatoh.m@gmail.com
90
+
91
+ The alias tracks account name changes.
92
+
93
+ > acm show google
94
+ NOTE: 'google' is alias for 'Gmail'.
95
+ Account: Ggmail
96
+ email: takatoh.m@gmail.com
97
+
98
+ And remove account:
99
+
100
+ > acm remove-account Gmail
101
+ Account: Gmail
102
+ email: takatoh.m@gmail.com
103
+
104
+ Are you sure?(y/n) y # Enter 'y' to remove.
105
+
106
+ > acm show Gmail
107
+ No such account: Gmail
108
+
109
+ The alias is also removed.
110
+
111
+ > acm show google
112
+ No such account: google
113
+
114
+ ## Special key: login-with
115
+
116
+ Special key `login-with` is reference to other account.
117
+
118
+ > acm add SomeWebService
119
+ (acm) Key? login-with
120
+ (acm) Value? GitHub
121
+ (acm) Key? # Enter to exit.
122
+
123
+ To track reference, use `acm show` command with `--track` option.
124
+
125
+ > acm show --track SomeWebService
126
+
127
+ ## License
128
+
129
+ MIT License
data/Rakefile CHANGED
@@ -1 +1 @@
1
- require "bundler/gem_tasks"
1
+ require "bundler/gem_tasks"
data/acm.gemspec CHANGED
@@ -1,34 +1,34 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'acm/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "acm"
8
- spec.version = Acm::VERSION
9
- spec.authors = ["takatoh"]
10
- spec.email = ["takatoh.m@gmail.com"]
11
-
12
- spec.summary = %q{A simple account manager (NOT SECURE ;p).}
13
- spec.description = %q{}
14
- spec.homepage = "https://github.com/takatoh/acm"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
- # delete this section to allow pushing this gem to any host.
19
- # if spec.respond_to?(:metadata)
20
- # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
- # else
22
- # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
- # end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 2.0"
31
- spec.add_development_dependency "rake", ">= 12.3.3"
32
- spec.add_runtime_dependency "thor"
33
- spec.add_runtime_dependency "clipboard"
34
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acm/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "acm"
8
+ spec.version = Acm::VERSION
9
+ spec.authors = ["takatoh"]
10
+ spec.email = ["takatoh.m@gmail.com"]
11
+
12
+ spec.summary = %q{A simple account manager (NOT SECURE ;p).}
13
+ spec.description = %q{}
14
+ spec.homepage = "https://github.com/takatoh/acm"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 2.2"
31
+ spec.add_development_dependency "rake", ">= 13.0"
32
+ spec.add_runtime_dependency "thor"
33
+ spec.add_runtime_dependency "clipboard"
34
+ end
data/bin/console CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "acm"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "acm"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup CHANGED
@@ -1,7 +1,7 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/exe/acm CHANGED
@@ -1,211 +1,284 @@
1
- #!/usr/bin/env ruby
2
- # -*- encoding: utf-8 -*-
3
-
4
- require 'acm'
5
- require 'thor'
6
- require 'yaml'
7
- require 'clipboard'
8
-
9
-
10
- class MyCLI < Thor
11
-
12
- DB_FILE = ENV['ACMDB'] || "#{ENV['HOME']}/.accounts"
13
- REFERENCE_KEY = "login-with"
14
-
15
- desc "init", "Init database"
16
- def init
17
- if File.exist?(DB_FILE)
18
- puts "Database file is already exist."
19
- else
20
- save_db([])
21
- end
22
- end
23
-
24
- desc "add ACCOUNT", "Add ACCOUNT"
25
- def add(account)
26
- db = load_db
27
- ac = lookup(account, db)
28
- if ac
29
- puts "Account #{account} is already exist."
30
- exit 0
31
- end
32
- details = {}
33
- ac = {
34
- "account" => account,
35
- "details" => details
36
- }
37
- while true
38
- print "(acm) Key? "
39
- key = STDIN.gets.chomp.strip
40
- break if key.empty?
41
- if key == "login-with"
42
- while true
43
- print "(acm) Value? "
44
- value = STDIN.gets.chomp.strip
45
- ref_account = lookup(value, db)
46
- if ref_account
47
- break
48
- else
49
- puts "#{value} not exist."
50
- end
51
- end
52
- else
53
- print "(acm) Value? "
54
- value = STDIN.gets.chomp.strip
55
- end
56
- details[key] = value
57
- end
58
- db << ac
59
- save_db(db)
60
- end
61
-
62
- desc "list", "List accounts"
63
- def list
64
- db = load_db
65
- db.map{|a| a['account'] }.sort.each{|a| puts a }
66
- end
67
-
68
- desc "search PATTERN", "Search accounts by PATTERN"
69
- def search(target)
70
- db = load_db
71
- accounts = search_accounts(target, db)
72
- if accounts.empty?
73
- puts "Not found: #{target}"
74
- else
75
- accounts.each{|a| puts a['account'] }
76
- end
77
- end
78
-
79
- desc "show [options] ACCOUNT", "Show details of ACCOUNT"
80
- option :pass, :type => :boolean, :aliases => "-p", :desc => "Show password"
81
- option :clip, :type => :boolean, :aliases => "-c", :desc => "Copy password to clipboard"
82
- option :track, :type => :boolean, :aliases => "-t", :desc => "Track referred account"
83
- def show(target)
84
- db = load_db
85
- account = lookup(target.encode("utf-8"), db)
86
- if account
87
- puts "Account: #{account['account']}"
88
- print_details(account['details'], options[:pass])
89
- copy_password(account['details'], options[:clip])
90
- if options[:track] && account['details'][REFERENCE_KEY]
91
- ref_account = lookup(account['details'][REFERENCE_KEY], db)
92
- if ref_account
93
- puts "\nReference: #{ref_account['account']}"
94
- print_details(ref_account['details'], options[:pass])
95
- copy_password(ref_account['details'], options[:clip])
96
- else
97
- puts "\nReference not found: #{account['details'][REFERENCE_KEY]}"
98
- end
99
- end
100
- else
101
- puts "No such account: #{target}"
102
- end
103
- end
104
-
105
- desc "update ACCOUNT KEY VALUE", "Update value of KEY in ACCOUNT"
106
- def update(target, key, value)
107
- db = load_db
108
- account = lookup(target.encode("utf-8"), db)
109
- if account
110
- account['details'][key] = value
111
- save_db(db)
112
- else
113
- puts "No such account: #{target}"
114
- end
115
- end
116
-
117
- desc "remove-key ACCOUNT KEY", "Remove KEY and value in ACCOUNT"
118
- def remove_key(target, key)
119
- db = load_db
120
- account = lookup(target.encode("utf-8"), db)
121
- if account
122
- account['details'].delete(key)
123
- save_db(db)
124
- else
125
- puts "No such account: #{target}"
126
- end
127
- end
128
-
129
- desc "remove-account ACCOUNT", "Remove ACCOUNT"
130
- def remove_account(target)
131
- db = load_db
132
- account = lookup(target.encode("utf-8"), db)
133
- if account
134
- puts "Account: #{target}"
135
- account['details'].each do |k, v|
136
- puts " #{k}: #{v}"
137
- end
138
- print "\nAre you sure?(y/n) "
139
- if STDIN.gets.chomp.downcase == "y"
140
- db.reject!{|a| a['account'] == target.encode("utf-8") }
141
- save_db(db)
142
- end
143
- else
144
- puts "No such account: #{target}"
145
- end
146
- end
147
-
148
- desc "rename-account OLD NEW", "Rename ACCOUNT"
149
- def rename_account(old, new)
150
- db = load_db
151
- account = lookup(old.encode("utf-8"), db)
152
- if account
153
- puts "Account: #{old} -> #{new}"
154
- account['account'] = new.encode("utf-8")
155
- save_db(db)
156
- else
157
- puts "No such account: #{old}"
158
- end
159
- end
160
-
161
- desc "version", "Show version and exit"
162
- def version
163
- puts "v#{Acm::VERSION}"
164
- end
165
-
166
-
167
- private
168
-
169
- def load_db
170
- begin
171
- YAML.load_file(DB_FILE)
172
- rescue
173
- puts "Error: Not found database file."
174
- exit(1)
175
- end
176
- end
177
-
178
- def lookup(target, db)
179
- db.find{|a| a['account'] == target }
180
- end
181
-
182
- def save_db(db)
183
- File.open(DB_FILE, "w"){|f| f.puts db.to_yaml }
184
- end
185
-
186
- def search_accounts(target, db)
187
- pattern = /#{target.encode("utf-8")}/i
188
- db.select{|a| pattern =~ a['account'].tr(" ", "") }
189
- end
190
-
191
- def print_details(details, pass = false)
192
- details.each do |key, val|
193
- if /pass/ =~ key && !pass
194
- puts " #{key}: ******"
195
- else
196
- puts " #{key}: #{val}"
197
- end
198
- end
199
- end
200
-
201
- def copy_password(details, clip = false)
202
- if clip
203
- password_key = details.keys.select{|k| /pass/ =~ k}.first
204
- Clipboard.copy(details[password_key])
205
- end
206
- end
207
-
208
- end # of class MyCLI
209
-
210
-
211
- MyCLI.start(ARGV)
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require "acm"
5
+ require "thor"
6
+ require "yaml"
7
+ require "clipboard"
8
+ require "fileutils"
9
+
10
+
11
+ class AcmCLI < Thor
12
+
13
+ DB_FILE = ENV['ACMDB'] || "#{ENV['HOME']}/.accounts"
14
+ REFERENCE_KEY = "login-with"
15
+
16
+ desc "init", "Init database"
17
+ def init
18
+ if File.exist?(DB_FILE)
19
+ puts "Database file is already exist."
20
+ else
21
+ init_db
22
+ end
23
+ end
24
+
25
+ desc "add ACCOUNT", "Add ACCOUNT"
26
+ def add(account)
27
+ db = load_db
28
+ ac = lookup(account, db)
29
+ if ac
30
+ puts "Account #{account} is already exist."
31
+ exit 0
32
+ end
33
+ details = {}
34
+ ac = {
35
+ "account" => account,
36
+ "details" => details
37
+ }
38
+ while true
39
+ print "(acm) Key? "
40
+ key = STDIN.gets.chomp.strip
41
+ break if key.empty?
42
+ if key == "login-with"
43
+ while true
44
+ print "(acm) Value? "
45
+ value = STDIN.gets.chomp.strip
46
+ ref_account = lookup(value, db)
47
+ if ref_account
48
+ break
49
+ else
50
+ puts "#{value} not exist."
51
+ end
52
+ end
53
+ else
54
+ print "(acm) Value? "
55
+ value = STDIN.gets.chomp.strip
56
+ end
57
+ details[key] = value
58
+ end
59
+ db << ac
60
+ save_db(db)
61
+ end
62
+
63
+ desc "list", "List accounts"
64
+ def list
65
+ db = load_db
66
+ db.sort_by{|a| a['account'] }.each do |a|
67
+ if a['alias_for']
68
+ puts "#{a['account']} -> #{a['alias_for']}"
69
+ else
70
+ puts a['account']
71
+ end
72
+ end
73
+ end
74
+
75
+ desc "search PATTERN", "Search accounts by PATTERN"
76
+ def search(target)
77
+ db = load_db
78
+ accounts = search_accounts(target, db)
79
+ if accounts.empty?
80
+ puts "Not found: #{target}"
81
+ else
82
+ accounts.each do |a|
83
+ if a['alias_for']
84
+ puts "#{a['account']} -> #{a['alias_for']}"
85
+ else
86
+ puts a['account']
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ desc "show [options] ACCOUNT", "Show details of ACCOUNT"
93
+ option :pass, :type => :boolean, :aliases => "-p", :desc => "Show password"
94
+ option :clip, :type => :boolean, :aliases => "-c", :desc => "Copy password to clipboard"
95
+ option :track, :type => :boolean, :aliases => "-t", :desc => "Track referred account"
96
+ def show(target)
97
+ db = load_db
98
+ account = lookup(target.encode("utf-8"), db)
99
+ if account && account['alias_for']
100
+ account = lookup(account['alias_for'], db)
101
+ puts "NOTE: '#{target}' is alias for '#{account['account']}'."
102
+ end
103
+ if account
104
+ puts "Account: #{account['account']}"
105
+ print_details(account['details'], options[:pass])
106
+ copy_password(account['details'], options[:clip])
107
+ if options[:track] && account['details'][REFERENCE_KEY]
108
+ ref_account = lookup(account['details'][REFERENCE_KEY], db)
109
+ if ref_account
110
+ puts "\nReference: #{ref_account['account']}"
111
+ print_details(ref_account['details'], options[:pass])
112
+ copy_password(ref_account['details'], options[:clip])
113
+ else
114
+ puts "\nReference not found: #{account['details'][REFERENCE_KEY]}"
115
+ end
116
+ end
117
+ else
118
+ puts "No such account: #{target}"
119
+ end
120
+ end
121
+
122
+ desc "update ACCOUNT KEY VALUE", "Update value of KEY in ACCOUNT"
123
+ def update(target, key, value)
124
+ db = load_db
125
+ account = lookup(target.encode("utf-8"), db)
126
+ if account
127
+ account['details'][key] = value
128
+ save_db(db)
129
+ else
130
+ puts "No such account: #{target}"
131
+ end
132
+ end
133
+
134
+ desc "remove-key ACCOUNT KEY", "Remove KEY and value in ACCOUNT"
135
+ def remove_key(target, key)
136
+ db = load_db
137
+ account = lookup(target.encode("utf-8"), db)
138
+ if account
139
+ account['details'].delete(key)
140
+ save_db(db)
141
+ else
142
+ puts "No such account: #{target}"
143
+ end
144
+ end
145
+
146
+ desc "remove-account ACCOUNT", "Remove ACCOUNT"
147
+ def remove_account(target)
148
+ db = load_db
149
+ account = lookup(target.encode("utf-8"), db)
150
+ if account
151
+ if account['alias_for']
152
+ puts "INFO: '#{target}' is alias for '#{account['alias_for']}'."
153
+ puts "Please run 'acm remove-account #{account['alias_for']}' to remove."
154
+ exit(0)
155
+ end
156
+ puts "Account: #{target}"
157
+ account['details'].each do |k, v|
158
+ puts " #{k}: #{v}"
159
+ end
160
+ aliases = search_alias(target.encode("utf-8"), db)
161
+ if aliases.size > 0
162
+ puts "Aliases: " + aliases.map{|al| al['account'] }.join(", ")
163
+ end
164
+ print "\nAre you sure?(y/n) "
165
+ if STDIN.gets.chomp.downcase == "y"
166
+ db.reject!{|ac| ac['account'] == target.encode("utf-8") }
167
+ aliases.each do |al|
168
+ db.reject!{|ac| ac['account'] == al['account'] }
169
+ end
170
+ save_db(db)
171
+ end
172
+ else
173
+ puts "No such account: #{target}"
174
+ end
175
+ end
176
+
177
+ desc "rename-account OLD NEW", "Rename ACCOUNT"
178
+ def rename_account(old, new)
179
+ db = load_db
180
+ account = lookup(old.encode("utf-8"), db)
181
+ if account
182
+ puts "Account: #{old} -> #{new}"
183
+ aliases = search_alias(old.encode("utf-8"), db)
184
+ account['account'] = new.encode("utf-8")
185
+ aliases.each{|al| al['alias_for'] = new.encode("utf-8") }
186
+ save_db(db)
187
+ else
188
+ puts "No such account: #{old}"
189
+ end
190
+ end
191
+
192
+ desc "env", "Display Environments"
193
+ def env
194
+ puts "Database file: #{DB_FILE}"
195
+ end
196
+
197
+ desc "alias ALIAS ACCOUNT", "Create an ALIAS for ACCOUNT"
198
+ def alias(from, dest)
199
+ db = load_db
200
+ ac = lookup(dest.encode("utf-8"), db)
201
+ if ac
202
+ puts "Create alias: #{from} for #{dest}"
203
+ al = {
204
+ "account" => from,
205
+ "alias_for" => ac['account']
206
+ }
207
+ db << al
208
+ save_db(db)
209
+ else
210
+ puts "No such account: #{dest}"
211
+ end
212
+ end
213
+
214
+ desc "remove-alias ALIAS", "Remove ALIAS"
215
+ def remove_alias(target)
216
+ db = load_db
217
+ ac = lookup(target.encode("utf-8"), db)
218
+ if ac
219
+ puts "Remove alias: #{target}"
220
+ db.reject!{|a| a['account'] == target.encode("utf-8") }
221
+ save_db(db)
222
+ else
223
+ puts "No such alias: #{target}"
224
+ end
225
+ end
226
+
227
+ desc "version", "Show version and exit"
228
+ def version
229
+ puts "v#{Acm::VERSION}"
230
+ end
231
+
232
+
233
+ private
234
+
235
+ def init_db
236
+ File.open(DB_FILE, "w"){|f| f.puts [].to_yaml }
237
+ FileUtils.chmod(0600, DB_FILE)
238
+ end
239
+
240
+ def load_db
241
+ YAML.load_file(DB_FILE)
242
+ rescue
243
+ puts "Error: Not found database file."
244
+ exit(1)
245
+ end
246
+
247
+ def lookup(target, db)
248
+ db.find{|a| a['account'] == target }
249
+ end
250
+
251
+ def save_db(db)
252
+ File.open(DB_FILE, "w"){|f| f.puts db.to_yaml }
253
+ end
254
+
255
+ def search_accounts(target, db)
256
+ pattern = /#{target.encode("utf-8")}/i
257
+ db.select{|a| pattern =~ a['account'].tr(" ", "") }
258
+ end
259
+
260
+ def search_alias(target, db)
261
+ db.select{|a| target == a['alias_for'] }
262
+ end
263
+
264
+ def print_details(details, pass = false)
265
+ details.each do |key, val|
266
+ if /pass/ =~ key && !pass
267
+ puts " #{key}: ******"
268
+ else
269
+ puts " #{key}: #{val}"
270
+ end
271
+ end
272
+ end
273
+
274
+ def copy_password(details, clip = false)
275
+ if clip
276
+ password_key = details.keys.select{|k| /pass/ =~ k}.first
277
+ Clipboard.copy(details[password_key])
278
+ end
279
+ end
280
+
281
+ end # of class AcmCLI
282
+
283
+
284
+ AcmCLI.start(ARGV)
data/lib/acm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Acm
2
- VERSION = "0.7.0"
3
- end
1
+ module Acm
2
+ VERSION = "0.8.0"
3
+ end
data/lib/acm.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "acm/version"
2
-
3
- module Acm
4
- # Your code goes here...
5
- end
1
+ require "acm/version"
2
+
3
+ module Acm
4
+ # Your code goes here...
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - takatoh
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-27 00:00:00.000000000 Z
11
+ date: 2023-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '2.2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '2.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 12.3.3
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 12.3.3
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: thor
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -90,7 +90,7 @@ homepage: https://github.com/takatoh/acm
90
90
  licenses:
91
91
  - MIT
92
92
  metadata: {}
93
- post_install_message:
93
+ post_install_message:
94
94
  rdoc_options: []
95
95
  require_paths:
96
96
  - lib
@@ -105,8 +105,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 3.0.1
109
- signing_key:
108
+ rubygems_version: 3.2.33
109
+ signing_key:
110
110
  specification_version: 4
111
111
  summary: A simple account manager (NOT SECURE ;p).
112
112
  test_files: []