acm 0.7.0 → 0.8.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 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: []