lib/mpw/cli.rb in mpw-4.0.0 vs lib/mpw/cli.rb in mpw-4.1.0
- old
+ new
@@ -1,19 +1,19 @@
#!/usr/bin/ruby
# MPW is a software to crypt and manage your passwords
-# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im>
-#
+# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im>
+#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'readline'
@@ -25,548 +25,556 @@
require 'tmpdir'
require 'mpw/item'
require 'mpw/mpw'
module MPW
-class Cli
+ class Cli
+ # Constructor
+ # @args: config -> the config
+ def initialize(config)
+ @config = config
+ end
- # Constructor
- # @args: config -> the config
- # sync -> boolean for sync or not
- def initialize(config, sync=true)
- @config = config
- @sync = sync
- end
+ # Change a parameter int the config after init
+ # @args: options -> param to change
+ def set_config(options)
+ @config.setup(options)
- # Change a parameter int the config after init
- # @args: options -> param to change
- def set_config(options)
- @config.setup(options)
+ puts I18n.t('form.set_config.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #15: #{e}".red
+ exit 2
+ end
- puts "#{I18n.t('form.set_config.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #15: #{e}".red
- exit 2
- end
+ # Change the wallet path
+ # @args: path -> the new path
+ def set_wallet_path(path)
+ @config.set_wallet_path(path, @wallet)
- # Create a new config file
- # @args: options -> set param
- def setup(options)
- options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1]
+ puts I18n.t('form.set_wallet_path.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #19: #{e}".red
+ exit 2
+ end
- I18n.locale = options[:lang].to_sym
+ # Create a new config file
+ # @args: options -> set param
+ def setup(options)
+ options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1]
- @config.setup(options)
+ I18n.locale = options[:lang].to_sym
- load_config
+ @config.setup(options)
- puts "#{I18n.t('form.setup_config.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #8: #{e}".red
- exit 2
- end
-
- # Setup a new GPG key
- # @args: gpg_key -> the key name
- def setup_gpg_key(gpg_key)
- return if @config.check_gpg_key?
+ load_config
- password = ask(I18n.t('form.setup_gpg_key.password')) {|q| q.echo = false}
- confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) {|q| q.echo = false}
+ puts I18n.t('form.setup_config.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #8: #{e}".red
+ exit 2
+ end
- if password != confirm
- raise I18n.t('form.setup_gpg_key.error_password')
- end
+ # Setup a new GPG key
+ # @args: gpg_key -> the key name
+ def setup_gpg_key(gpg_key)
+ return if @config.check_gpg_key?
- @password = password.to_s
+ password = ask(I18n.t('form.setup_gpg_key.password')) { |q| q.echo = false }
+ confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) { |q| q.echo = false }
- puts I18n.t('form.setup_gpg_key.wait')
-
- @config.setup_gpg_key(@password, gpg_key)
+ raise I18n.t('form.setup_gpg_key.error_password') if password != confirm
- puts "#{I18n.t('form.setup_gpg_key.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #8: #{e}".red
- exit 2
- end
+ @password = password.to_s
- # Setup wallet config for sync
- # @args: options -> value to change
- def setup_wallet_config(options={})
- if not options[:password].nil?
- options[:password] = ask(I18n.t('form.setup_wallet.password')) {|q| q.echo = false}
- end
+ puts I18n.t('form.setup_gpg_key.wait')
- #wallet_file = wallet.nil? ? "#{@config.wallet_dir}/default.mpw" : "#{@config.wallet_dir}/#{wallet}.mpw"
+ @config.setup_gpg_key(@password, gpg_key)
- @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe)
- @mpw.read_data
- @mpw.set_config(options)
- @mpw.write_data
+ puts I18n.t('form.setup_gpg_key.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #8: #{e}".red
+ exit 2
+ end
- puts "#{I18n.t('form.setup_wallet.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #10: #{e}".red
- exit 2
- end
-
- # List gpg keys in wallet
- def list_keys
- table_list('keys', @mpw.list_keys)
- end
+ # List gpg keys in wallet
+ def list_keys
+ table_list('keys', @mpw.list_keys)
+ end
- # Load config
- def load_config
- @config.load_config
+ # List config
+ def list_config
+ config = {
+ 'lang' => @config.lang,
+ 'gpg_key' => @config.gpg_key,
+ 'default_wallet' => @config.default_wallet,
+ 'config_dir' => @config.config_dir,
+ 'pinmode' => @config.pinmode,
+ 'gpg_exe' => @config.gpg_exe
+ }
- rescue Exception => e
- puts "#{I18n.t('display.error')} #10: #{e}".red
- exit 2
- end
+ @config.wallet_paths.each { |k, v| config["path_wallet_#{k}"] = "#{v}/#{k}.mpw" }
+ @config.password.each { |k, v| config["password_#{k}"] = v }
- # Request the GPG password and decrypt the file
- def decrypt
- if not defined?(@mpw)
- @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false}
- @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe)
- end
+ table_list('config', config)
+ end
- @mpw.read_data
- @mpw.sync if @sync
- rescue Exception => e
- puts "#{I18n.t('display.error')} #11: #{e}".red
- exit 2
- end
+ # Load config
+ def load_config
+ @config.load_config
+ rescue => e
+ puts "#{I18n.t('display.error')} #10: #{e}".red
+ exit 2
+ end
- # Format list on a table
- def table_list(title, list)
- i = 1
- length = 0
+ # Request the GPG password and decrypt the file
+ def decrypt
+ unless defined?(@mpw)
+ @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false }
+ @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe, @config.pinmode)
+ end
- list.each do |item|
- length = item.length if length < item.length
- end
- length += 7
+ @mpw.read_data
+ rescue => e
+ puts "#{I18n.t('display.error')} #11: #{e}".red
+ exit 2
+ end
- puts "\n#{I18n.t("display.#{title}")}".red
- print ' '
- length.times { print '=' }
- print "\n"
+ # Format list on a table
+ # @args: title -> the name of table
+ # list -> array or hash
+ def table_list(title, list)
+ length = { k: 0, v: 0 }
- list.each do |item|
- print " #{i}".cyan
- (3 - i.to_s.length).times { print ' ' }
- puts "| #{item}"
- i += 1
- end
+ if list.is_a?(Array)
+ i = 0
+ list = list.map do |item|
+ i += 1
+ [i, item]
+ end.to_h
+ end
- print "\n"
- end
+ list.each do |k, v|
+ length[:k] = k.to_s.length if length[:k] < k.to_s.length
+ length[:v] = v.to_s.length if length[:v] < v.to_s.length
+ end
- # Format items on a table
- def table_items(items=[])
- group = '.'
- i = 1
- length_total = 10
- data = { id: { length: 3, color: 'cyan' },
- host: { length: 9, color: 'yellow' },
- user: { length: 7, color: 'green' },
- protocol: { length: 9, color: 'white' },
- port: { length: 5, color: 'white' },
- otp: { length: 4, color: 'white' },
- comment: { length: 14, color: 'magenta' },
- }
+ puts "\n#{I18n.t("display.#{title}")}".red
+ print ' '
+ (length[:k] + length[:v] + 5).times { print '=' }
+ print "\n"
- items.each do |item|
- data.each do |k, v|
- next if k == :id or k == :otp
+ list.each do |k, v|
+ print " #{k}".cyan
+ (length[:k] - k.to_s.length + 1).times { print ' ' }
+ puts "| #{v}"
+ end
- v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length]
- end
- end
- data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length]
-
- data.each_value { |v| length_total += v[:length] }
- items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase }
+ print "\n"
+ end
- items.each do |item|
- if group != item.group
- group = item.group
+ # Format items on a table
+ # @args: items -> an aray items
+ def table_items(items = [])
+ group = '.'
+ i = 1
+ length_total = 10
+ data = { id: { length: 3, color: 'cyan' },
+ host: { length: 9, color: 'yellow' },
+ user: { length: 7, color: 'green' },
+ protocol: { length: 9, color: 'white' },
+ port: { length: 5, color: 'white' },
+ otp: { length: 4, color: 'white' },
+ comment: { length: 14, color: 'magenta' } }
- if group.to_s.empty?
- puts "\n#{I18n.t('display.no_group')}".red
- else
- puts "\n#{group}".red
- end
+ items.each do |item|
+ data.each do |k, v|
+ next if k == :id || k == :otp
- print ' '
- length_total.times { print '=' }
- print "\n "
- data.each do |k, v|
- case k
- when :id
- print ' ID'
- when :otp
- print '| OTP'
- else
- print "| #{k.to_s.capitalize}"
- end
+ v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length]
+ end
+ end
+ data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length]
- (v[:length] - k.to_s.length).times { print ' ' }
- end
- print "\n "
- length_total.times { print '=' }
- print "\n"
- end
+ data.each_value { |v| length_total += v[:length] }
+ items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase }
- print " #{i}".send(data[:id][:color])
- (data[:id][:length] - i.to_s.length).times { print ' ' }
- data.each do |k, v|
- next if k == :id
+ items.each do |item|
+ if group != item.group
+ group = item.group
- if k == :otp
- print '| '
- if item.otp; print ' X ' else 4.times { print ' ' } end
+ if group.to_s.empty?
+ puts "\n#{I18n.t('display.no_group')}".red
+ else
+ puts "\n#{group}".red
+ end
- next
- end
+ print ' '
+ length_total.times { print '=' }
+ print "\n "
+ data.each do |k, v|
+ case k
+ when :id
+ print ' ID'
+ when :otp
+ print '| OTP'
+ else
+ print "| #{k.to_s.capitalize}"
+ end
- print '| '
- print "#{item.send(k.to_s)}".send(v[:color])
- (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' }
- end
- print "\n"
+ (v[:length] - k.to_s.length).times { print ' ' }
+ end
+ print "\n "
+ length_total.times { print '=' }
+ print "\n"
+ end
- i += 1
- end
+ print " #{i}".send(data[:id][:color])
+ (data[:id][:length] - i.to_s.length).times { print ' ' }
+ data.each do |k, v|
+ next if k == :id
- print "\n"
- end
+ if k == :otp
+ print '| '
+ item.otp ? (print ' X ') : 4.times { print ' ' }
- # Display the query's result
- # @args: options -> the option to search
- def list(options={})
- result = @mpw.list(options)
+ next
+ end
- if result.length == 0
- puts I18n.t('display.nothing')
- else
- table_items(result)
- end
- end
+ print '| '
+ print item.send(k.to_s).to_s.send(v[:color])
+ (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' }
+ end
+ print "\n"
- # Get an item when multiple choice
- # @args: items -> array of items
- # @rtrn: item
- def get_item(items)
- return items[0] if items.length == 1
+ i += 1
+ end
- items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase }
- choice = ask(I18n.t('form.select')).to_i
+ print "\n"
+ end
- if choice >= 1 and choice <= items.length
- return items[choice-1]
- else
- return nil
- end
- end
+ # Display the query's result
+ # @args: options -> the option to search
+ def list(**options)
+ result = @mpw.list(options)
- # Copy in clipboard the login and password
- # @args: item -> the item
- # clipboard -> enable clipboard
- def clipboard(item, clipboard=true)
- pid = nil
+ if result.empty?
+ puts I18n.t('display.nothing')
+ else
+ table_items(result)
+ end
+ end
- # Security: force quit after 90s
- Thread.new do
- sleep 90
- exit
- end
-
- while true
- choice = ask(I18n.t('form.clipboard.choice')).to_s
-
- case choice
- when 'q', 'quit'
- break
+ # Get an item when multiple choice
+ # @args: items -> array of items
+ # @rtrn: item
+ def get_item(items)
+ return items[0] if items.length == 1
- when 'l', 'login'
- if clipboard
- Clipboard.copy(item.user)
- puts I18n.t('form.clipboard.login').green
- else
- puts item.user
- end
+ items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase }
+ choice = ask(I18n.t('form.select')).to_i
- when 'p', 'password'
- if clipboard
- Clipboard.copy(@mpw.get_password(item.id))
- puts I18n.t('form.clipboard.password').yellow
+ choice >= 1 && choice <= items.length ? items[choice - 1] : nil
+ end
- Thread.new do
- sleep 30
+ # Copy in clipboard the login and password
+ # @args: item -> the item
+ # clipboard -> enable clipboard
+ def clipboard(item, clipboard = true)
+ # Security: force quit after 90s
+ Thread.new do
+ sleep 90
+ exit
+ end
- Clipboard.clear
- end
- else
- puts @mpw.get_password(item.id)
- end
+ Kernel.loop do
+ choice = ask(I18n.t('form.clipboard.choice')).to_s
- when 'o', 'otp'
- if clipboard
- Clipboard.copy(@mpw.get_otp_code(item.id))
- else
- puts @mpw.get_otp_code(item.id)
- end
- puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow
+ case choice
+ when 'q', 'quit'
+ break
- else
- puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan
- puts I18n.t('form.clipboard.help.login')
- puts I18n.t('form.clipboard.help.password')
- puts I18n.t('form.clipboard.help.otp_code')
- puts I18n.t('form.clipboard.help.quit')
- next
- end
- end
+ when 'l', 'login'
+ if clipboard
+ Clipboard.copy(item.user)
+ puts I18n.t('form.clipboard.login').green
+ else
+ puts item.user
+ end
- Clipboard.clear
- rescue SystemExit, Interrupt
- Clipboard.clear
- end
+ when 'p', 'password'
+ if clipboard
+ Clipboard.copy(@mpw.get_password(item.id))
+ puts I18n.t('form.clipboard.password').yellow
- # List all wallets
- def list_wallet
- wallets = []
- Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f|
- wallet = File.basename(f, '.mpw')
- wallet += ' *'.green if wallet == @config.default_wallet
- wallets << wallet
- end
+ Thread.new do
+ sleep 30
- table_list('wallets', wallets)
- end
+ Clipboard.clear
+ end
+ else
+ puts @mpw.get_password(item.id)
+ end
- # Display the wallet
- # @args: wallet -> the wallet name
- def get_wallet(wallet=nil)
- if wallet.to_s.empty?
- wallets = Dir.glob("#{@config.wallet_dir}/*.mpw")
+ when 'o', 'otp'
+ if clipboard
+ Clipboard.copy(@mpw.get_otp_code(item.id))
+ else
+ puts @mpw.get_otp_code(item.id)
+ end
+ puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow
- if wallets.length == 1
- @wallet_file = wallets[0]
- elsif not @config.default_wallet.to_s.empty?
- @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw"
- else
- @wallet_file = "#{@config.wallet_dir}/default.mpw"
- end
- else
- @wallet_file = "#{@config.wallet_dir}/#{wallet}.mpw"
- end
- end
+ else
+ puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan
+ puts I18n.t('form.clipboard.help.login')
+ puts I18n.t('form.clipboard.help.password')
+ puts I18n.t('form.clipboard.help.otp_code')
+ puts I18n.t('form.clipboard.help.quit')
+ next
+ end
+ end
- # Add a new public key
- # args: key -> the key name or key file to add
- def add_key(key)
- @mpw.add_key(key)
- @mpw.write_data
- @mpw.sync(true) if @sync
+ Clipboard.clear
+ rescue SystemExit, Interrupt
+ Clipboard.clear
+ end
- puts "#{I18n.t('form.add_key.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #13: #{e}".red
- end
+ # List all wallets
+ def list_wallet
+ wallets = []
+ Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f|
+ wallet = File.basename(f, '.mpw')
+ wallet += ' *'.green if wallet == @config.default_wallet
+ wallets << wallet
+ end
- # Add new public key
- # args: key -> the key name to delete
- def delete_key(key)
- @mpw.delete_key(key)
- @mpw.write_data
- @mpw.sync(true) if @sync
+ table_list('wallets', wallets)
+ end
- puts "#{I18n.t('form.delete_key.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #15: #{e}".red
- end
+ # Display the wallet
+ # @args: wallet -> the wallet name
+ def get_wallet(wallet = nil)
+ @wallet =
+ if wallet.to_s.empty?
+ wallets = Dir.glob("#{@config.wallet_dir}/*.mpw")
+ if wallets.length == 1
+ File.basename(wallets[0], '.mpw')
+ elsif !@config.default_wallet.to_s.empty?
+ @config.default_wallet
+ else
+ 'default'
+ end
+ else
+ wallet
+ end
- # Text editor interface
- # @args: template -> template name
- # item -> the item to edit
- # password -> disable field password
- def text_editor(template_name, item=nil, password=false)
- editor = ENV['EDITOR'] || 'nano'
- options = {}
- opts = {}
- template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb"
- template = ERB.new(IO.read(template_file))
+ @wallet_file =
+ if @config.wallet_paths.key?(@wallet)
+ "#{@config.wallet_paths[@wallet]}/#{@wallet}.mpw"
+ else
+ "#{@config.wallet_dir}/#{@wallet}.mpw"
+ end
+ end
- Dir.mktmpdir do |dir|
- tmp_file = "#{dir}/#{template_name}.yml"
+ # Add a new public key
+ # args: key -> the key name or key file to add
+ def add_key(key)
+ @mpw.add_key(key)
+ @mpw.write_data
- File.open(tmp_file, 'w') do |f|
- f << template.result(binding)
- end
+ puts I18n.t('form.add_key.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #13: #{e}".red
+ end
- system("#{editor} #{tmp_file}")
+ # Add new public key
+ # args: key -> the key name to delete
+ def delete_key(key)
+ @mpw.delete_key(key)
+ @mpw.write_data
- opts = YAML::load_file(tmp_file)
- end
+ puts I18n.t('form.delete_key.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #15: #{e}".red
+ end
- opts.delete_if { |k,v| v.to_s.empty? }
+ # Text editor interface
+ # @args: template -> template name
+ # item -> the item to edit
+ # password -> disable field password
+ # @rtrn: a hash with the value for an item
+ def text_editor(template_name, password = false, item = nil, **options)
+ editor = ENV['EDITOR'] || 'nano'
+ opts = {}
+ template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb"
+ template = ERB.new(IO.read(template_file))
- opts.each do |k,v|
- options[k.to_sym] = v
- end
+ Dir.mktmpdir do |dir|
+ tmp_file = "#{dir}/#{template_name}.yml"
- return options
- end
+ File.open(tmp_file, 'w') do |f|
+ f << template.result(binding)
+ end
- # Form to add a new item
- # @args: password -> generate a random password
- def add(password=false)
- options = text_editor('add_form', nil, password)
- item = Item.new(options)
- options[:password] = MPW::password(@config.password) if password
-
- @mpw.add(item)
- @mpw.set_password(item.id, options[:password]) if options.has_key?(:password)
- @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key)
- @mpw.write_data
- @mpw.sync(true) if @sync
+ system("#{editor} #{tmp_file}")
- puts "#{I18n.t('form.add_item.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #13: #{e}".red
- end
+ opts = YAML.load_file(tmp_file)
+ end
- # Update an item
- # @args: password -> generate a random password
- # options -> the option to search
- def update(password=false, options={})
- items = @mpw.list(options)
-
- if items.length == 0
- puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow
- else
- table_items(items) if items.length > 1
+ opts.delete_if { |_, v| v.to_s.empty? }
- item = get_item(items)
- options = text_editor('update_form', item, password)
- options[:password] = MPW::password(@config.password) if password
+ opts.each do |k, v|
+ options[k.to_sym] = v
+ end
- item.update(options)
- @mpw.set_password(item.id, options[:password]) if options.has_key?(:password)
- @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key)
- @mpw.write_data
- @mpw.sync(true) if @sync
+ options
+ end
- puts "#{I18n.t('form.update_item.valid')}".green
- end
- rescue Exception => e
- puts "#{I18n.t('display.error')} #14: #{e}".red
- end
+ # Form to add a new item
+ # @args: password -> generate a random password
+ # text_editor -> enable text editor mode
+ # values -> hash with multiples value to set the item
+ def add(password = false, text_editor = false, **values)
+ options = text_editor('add_form', password, nil, values) if text_editor
+ item = Item.new(options)
+ options[:password] = MPW.password(@config.password) if password
- # Remove an item
- # @args: options -> the option to search
- def delete(options={})
- items = @mpw.list(options)
-
- if items.length == 0
- puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow
- else
- table_items(items)
+ @mpw.add(item)
+ @mpw.set_password(item.id, options[:password]) if options.key?(:password)
+ @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key)
+ @mpw.write_data
- item = get_item(items)
- confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s
-
- if not confirm =~ /^(y|yes|YES|Yes|Y)$/
- return false
- end
-
- item.delete
- @mpw.write_data
- @mpw.sync(true) if @sync
-
- puts "#{I18n.t('form.delete_item.valid')}".green
- end
- rescue Exception => e
- puts "#{I18n.t('display.error')} #16: #{e}".red
- end
+ puts I18n.t('form.add_item.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #13: #{e}".red
+ end
- # Copy a password, otp, login
- # @args: clipboard -> enable clipboard
- # options -> the option to search
- def copy(clipboard=true, options={})
- items = @mpw.list(options)
-
- if items.length == 0
- puts I18n.t('display.nothing')
- else
- table_items(items)
+ # Update an item
+ # @args: password -> generate a random password
+ # text_editor -> enable text editor mode
+ # options -> the option to search
+ # values -> hash with multiples value to set the item
+ def update(password = false, text_editor = false, options = {}, **values)
+ items = @mpw.list(options)
- item = get_item(items)
- clipboard(item, clipboard)
- end
- rescue Exception => e
- puts "#{I18n.t('display.error')} #14: #{e}".red
- end
+ if items.empty?
+ puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow
+ else
+ table_items(items) if items.length > 1
- # Export the items in a CSV file
- # @args: file -> the destination file
- # options -> option to search
- def export(file, options)
- file = 'export-mpw.yml' if file.to_s.empty?
- items = @mpw.list(options)
- data = {}
+ item = get_item(items)
+ values = text_editor('update_form', password, item, values) if text_editor
+ values[:password] = MPW.password(@config.password) if password
- items.each do |item|
- data.merge!(item.id => { 'host' => item.host,
- 'user' => item.user,
- 'group' => item.group,
- 'password' => @mpw.get_password(item.id),
- 'protocol' => item.protocol,
- 'port' => item.port,
- 'otp_key' => @mpw.get_otp_key(item.id),
- 'comment' => item.comment,
- 'last_edit' => item.last_edit,
- 'created' => item.created,
- }
- )
- end
+ item.update(values)
+ @mpw.set_password(item.id, values[:password]) if values.key?(:password)
+ @mpw.set_otp_key(item.id, values[:otp_key]) if values.key?(:otp_key)
+ @mpw.write_data
- File.open(file, 'w') {|f| f << data.to_yaml}
+ puts I18n.t('form.update_item.valid').to_s.green
+ end
+ rescue => e
+ puts "#{I18n.t('display.error')} #14: #{e}".red
+ end
- puts "#{I18n.t('form.export.valid', file: file)}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #17: #{e}".red
- end
+ # Remove an item
+ # @args: options -> the option to search
+ def delete(**options)
+ items = @mpw.list(options)
- # Import items from a YAML file
- # @args: file -> the import file
- def import(file)
- raise I18n.t('form.import.file_empty') if file.to_s.empty?
- raise I18n.t('form.import.file_not_exist') if not File.exist?(file)
+ if items.empty?
+ puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow
+ else
+ table_items(items)
- YAML::load_file(file).each_value do |row|
- item = Item.new(group: row['group'],
- host: row['host'],
- protocol: row['protocol'],
- user: row['user'],
- port: row['port'],
- comment: row['comment'],
- )
+ item = get_item(items)
+ confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s
- next if item.empty?
+ return unless confirm =~ /^(y|yes|YES|Yes|Y)$/
- @mpw.add(item)
- @mpw.set_password(item.id, row['password']) if not row['password'].to_s.empty?
- @mpw.set_otp_key(item.id, row['otp_key']) if not row['otp_key'].to_s.empty?
- end
+ item.delete
+ @mpw.write_data
- @mpw.write_data
+ puts I18n.t('form.delete_item.valid').to_s.green
+ end
+ rescue => e
+ puts "#{I18n.t('display.error')} #16: #{e}".red
+ end
- puts "#{I18n.t('form.import.valid')}".green
- rescue Exception => e
- puts "#{I18n.t('display.error')} #18: #{e}".red
- end
-end
+ # Copy a password, otp, login
+ # @args: clipboard -> enable clipboard
+ # options -> the option to search
+ def copy(clipboard = true, **options)
+ items = @mpw.list(options)
+
+ if items.empty?
+ puts I18n.t('display.nothing')
+ else
+ table_items(items)
+
+ item = get_item(items)
+ clipboard(item, clipboard)
+ end
+ rescue => e
+ puts "#{I18n.t('display.error')} #14: #{e}".red
+ end
+
+ # Export the items in a CSV file
+ # @args: file -> the destination file
+ # options -> option to search
+ def export(file, options)
+ file = 'export-mpw.yml' if file.to_s.empty?
+ items = @mpw.list(options)
+ data = {}
+
+ items.each do |item|
+ data.merge!(
+ item.id => {
+ 'host' => item.host,
+ 'user' => item.user,
+ 'group' => item.group,
+ 'password' => @mpw.get_password(item.id),
+ 'protocol' => item.protocol,
+ 'port' => item.port,
+ 'otp_key' => @mpw.get_otp_key(item.id),
+ 'comment' => item.comment,
+ 'last_edit' => item.last_edit,
+ 'created' => item.created,
+ }
+ )
+ end
+
+ File.open(file, 'w') { |f| f << data.to_yaml }
+
+ puts I18n.t('form.export.valid', file: file).to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #17: #{e}".red
+ end
+
+ # Import items from a YAML file
+ # @args: file -> the import file
+ def import(file)
+ raise I18n.t('form.import.file_empty') if file.to_s.empty?
+ raise I18n.t('form.import.file_not_exist') unless File.exist?(file)
+
+ YAML.load_file(file).each_value do |row|
+ item = Item.new(group: row['group'],
+ host: row['host'],
+ protocol: row['protocol'],
+ user: row['user'],
+ port: row['port'],
+ comment: row['comment'])
+
+ next if item.empty?
+
+ @mpw.add(item)
+ @mpw.set_password(item.id, row['password']) unless row['password'].to_s.empty?
+ @mpw.set_otp_key(item.id, row['otp_key']) unless row['otp_key'].to_s.empty?
+ end
+
+ @mpw.write_data
+
+ puts I18n.t('form.import.valid').to_s.green
+ rescue => e
+ puts "#{I18n.t('display.error')} #18: #{e}".red
+ end
+ end
end