mirror of
https://github.com/nishiki/manage-password.git
synced 2025-02-17 08:30:04 +00:00
rewrite mpw for use a new file storage format
This commit is contained in:
parent
0268c60484
commit
408ee95bcc
5 changed files with 532 additions and 739 deletions
22
bin/mpw
22
bin/mpw
|
@ -1,7 +1,6 @@
|
|||
#!/usr/bin/ruby
|
||||
# author: nishiki
|
||||
# mail: nishiki@yaegashi.fr
|
||||
# info: a simple script who manage your passwords
|
||||
|
||||
require 'rubygems'
|
||||
require 'optparse'
|
||||
|
@ -11,7 +10,7 @@ require 'set'
|
|||
require 'i18n'
|
||||
require 'mpw/mpw'
|
||||
require 'mpw/config'
|
||||
require 'mpw/ui/cli'
|
||||
require 'mpw/cli'
|
||||
|
||||
# --------------------------------------------------------- #
|
||||
# Set local
|
||||
|
@ -77,26 +76,12 @@ OptionParser.new do |opts|
|
|||
options[:setup] = true
|
||||
end
|
||||
|
||||
opts.on('-p', '--protocol PROTOCOL', I18n.t('option.protocol')) do |protocol|
|
||||
options[:protocol] = protocol
|
||||
end
|
||||
|
||||
opts.on('-e', '--export FILE', I18n.t('option.export')) do |file|
|
||||
options[:export] = file
|
||||
options[:type] = :yaml
|
||||
end
|
||||
|
||||
opts.on('-t', '--type TYPE', I18n.t('option.type')) do |type|
|
||||
options[:type] = type.to_sym
|
||||
end
|
||||
|
||||
opts.on('-i', '--import FILE', I18n.t('option.import')) do |file|
|
||||
options[:import] = file
|
||||
options[:type] = :yaml
|
||||
end
|
||||
|
||||
opts.on('-f', '--force', I18n.t('option.force')) do
|
||||
options[:force] = true
|
||||
end
|
||||
|
||||
opts.on('-N', '--no-sync', I18n.t('option.no_sync')) do
|
||||
|
@ -131,7 +116,6 @@ elsif not config.check_gpg_key?
|
|||
end
|
||||
|
||||
cli.decrypt
|
||||
cli.sync(options[:sync])
|
||||
|
||||
# Display the item's informations
|
||||
if not options[:show].nil?
|
||||
|
@ -156,11 +140,11 @@ elsif not options[:add].nil?
|
|||
|
||||
# Export
|
||||
elsif not options[:export].nil?
|
||||
cli.export(options[:export], options[:type])
|
||||
cli.export(options[:export])
|
||||
|
||||
# Add a new item
|
||||
elsif not options[:import].nil?
|
||||
cli.import(options[:import], options[:type], options[:force])
|
||||
cli.import(options[:import])
|
||||
|
||||
# Interactive mode
|
||||
end
|
||||
|
|
|
@ -2,230 +2,158 @@
|
|||
# author: nishiki
|
||||
# mail: nishiki@yaegashi.fr
|
||||
|
||||
require 'rubygems'
|
||||
require 'gpgme'
|
||||
require 'yaml'
|
||||
require 'i18n'
|
||||
|
||||
module MPW
|
||||
class Config
|
||||
|
||||
attr_accessor :error_msg
|
||||
class Config
|
||||
|
||||
attr_accessor :key
|
||||
attr_accessor :share_keys
|
||||
attr_accessor :lang
|
||||
attr_accessor :file_gpg
|
||||
attr_accessor :last_update
|
||||
attr_accessor :sync_type
|
||||
attr_accessor :sync_host
|
||||
attr_accessor :sync_port
|
||||
attr_accessor :sync_user
|
||||
attr_accessor :sync_pwd
|
||||
attr_accessor :sync_path
|
||||
attr_accessor :last_sync
|
||||
attr_accessor :dir_config
|
||||
|
||||
# Constructor
|
||||
# @args: file_config -> the specify config file
|
||||
def initialize(file_config=nil)
|
||||
@error_msg = nil
|
||||
attr_accessor :error_msg
|
||||
|
||||
if /darwin/ =~ RUBY_PLATFORM
|
||||
@dir_config = "#{Dir.home}/Library/Preferences/mpw"
|
||||
elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
|
||||
@dir_config = "#{Dir.home}/AppData/Local/mpw"
|
||||
else
|
||||
@dir_config = "#{Dir.home}/.config/mpw"
|
||||
end
|
||||
|
||||
@file_config = "#{@dir_config}/conf/default.cfg"
|
||||
if not file_config.nil? and not file_config.empty?
|
||||
@file_config = file_config
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new config file
|
||||
# @args: key -> the gpg key to encrypt
|
||||
# share_keys -> multiple keys to share the password with other people
|
||||
# lang -> the software language
|
||||
# file_gpg -> the file who is encrypted
|
||||
# sync_type -> the type to synchronization
|
||||
# sync_host -> the server host for synchronization
|
||||
# sync_port -> the server port for synchronization
|
||||
# sync_user -> the user for synchronization
|
||||
# sync_pwd -> the password for synchronization
|
||||
# sync_suffix -> the suffix file (optionnal)
|
||||
# @rtrn: true if le config file is create
|
||||
def setup(key, share_keys, lang, file_gpg, sync_type, sync_host, sync_port, sync_user, sync_pwd, sync_path)
|
||||
|
||||
if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
|
||||
@error_msg = I18n.t('error.config.key_bad_format')
|
||||
return false
|
||||
end
|
||||
attr_accessor :key
|
||||
attr_accessor :lang
|
||||
attr_accessor :config_dir
|
||||
attr_accessor :wallet_dir
|
||||
|
||||
if not check_public_gpg_key(share_keys)
|
||||
return false
|
||||
end
|
||||
|
||||
if file_gpg.empty?
|
||||
file_gpg = "#{@dir_config}/db/default.gpg"
|
||||
end
|
||||
|
||||
config = {'config' => {'key' => key,
|
||||
'share_keys' => share_keys,
|
||||
'lang' => lang,
|
||||
'file_gpg' => file_gpg,
|
||||
'sync_type' => sync_type,
|
||||
'sync_host' => sync_host,
|
||||
'sync_port' => sync_port,
|
||||
'sync_user' => sync_user,
|
||||
'sync_pwd' => sync_pwd,
|
||||
'sync_path' => sync_path,
|
||||
'last_sync' => 0
|
||||
}
|
||||
}
|
||||
|
||||
Dir.mkdir("#{@config_dir}/conf", 700)
|
||||
Dir.mkdir("#{@config_dir}/db", 700)
|
||||
File.open(@file_config, 'w') do |file|
|
||||
file << config.to_yaml
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
# Constructor
|
||||
# @args: config_file -> the specify config file
|
||||
def initialize(config_file=nil)
|
||||
@error_msg = nil
|
||||
@config_file = config_file
|
||||
|
||||
# Setup a new gpg key
|
||||
# @args: password -> the GPG key password
|
||||
# name -> the name of user
|
||||
# length -> length of the GPG key
|
||||
# expire -> the time of expire to GPG key
|
||||
# @rtrn: true if the GPG key is create, else false
|
||||
def setup_gpg_key(password, name, length = 2048, expire = 0)
|
||||
if name.nil? or name.empty?
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.name')}"
|
||||
return false
|
||||
elsif password.nil? or password.empty?
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.password')}"
|
||||
return false
|
||||
end
|
||||
|
||||
param = ''
|
||||
param << '<GnupgKeyParms format="internal">' + "\n"
|
||||
param << "Key-Type: DSA\n"
|
||||
param << "Key-Length: #{length}\n"
|
||||
param << "Subkey-Type: ELG-E\n"
|
||||
param << "Subkey-Length: #{length}\n"
|
||||
param << "Name-Real: #{name}\n"
|
||||
param << "Name-Comment: #{name}\n"
|
||||
param << "Name-Email: #{@key}\n"
|
||||
param << "Expire-Date: #{expire}\n"
|
||||
param << "Passphrase: #{password}\n"
|
||||
param << "</GnupgKeyParms>\n"
|
||||
|
||||
ctx = GPGME::Ctx.new
|
||||
ctx.genkey(param, nil, nil)
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Check the config file
|
||||
# @rtrn: true if the config file is correct
|
||||
def checkconfig
|
||||
config = YAML::load_file(@file_config)
|
||||
@key = config['config']['key']
|
||||
@share_keys = config['config']['share_keys']
|
||||
@lang = config['config']['lang']
|
||||
@file_gpg = config['config']['file_gpg']
|
||||
@sync_type = config['config']['sync_type']
|
||||
@sync_host = config['config']['sync_host']
|
||||
@sync_port = config['config']['sync_port']
|
||||
@sync_user = config['config']['sync_user']
|
||||
@sync_pwd = config['config']['sync_pwd']
|
||||
@sync_path = config['config']['sync_path']
|
||||
@last_sync = config['config']['last_sync'].to_i
|
||||
|
||||
if @key.empty? or @file_gpg.empty?
|
||||
@error_msg = I18n.t('error.config.check')
|
||||
return false
|
||||
end
|
||||
I18n.locale = @lang.to_sym
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.check')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Check if private key exist
|
||||
# @rtrn: true if the key exist, else false
|
||||
def check_gpg_key?
|
||||
ctx = GPGME::Ctx.new
|
||||
ctx.each_key(@key, true) do
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
# Check if private key exist
|
||||
# @args: share_keys -> string with all public keys
|
||||
# @rtrn: true if the key exist, else false
|
||||
def check_public_gpg_key(share_keys = @share_keys)
|
||||
ctx = GPGME::Ctx.new
|
||||
|
||||
share_keys = share_keys.nil? ? '' : share_keys
|
||||
if not share_keys.empty?
|
||||
share_keys.split.each do |k|
|
||||
if not k =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
|
||||
@error_msg = I18n.t('error.config.key_bad_format')
|
||||
return false
|
||||
end
|
||||
|
||||
ctx.each_key(key, false) do
|
||||
next
|
||||
end
|
||||
|
||||
@error_msg = I18n.t('error.config.no_key_public', key: k)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
# Set the last update when there is a sync
|
||||
# @rtrn: true is the file has been updated
|
||||
def set_last_sync
|
||||
config = {'config' => {'key' => @key,
|
||||
'share_keys' => @share_keys,
|
||||
'lang' => @lang,
|
||||
'file_gpg' => @file_gpg,
|
||||
'sync_type' => @sync_type,
|
||||
'sync_host' => @sync_host,
|
||||
'sync_port' => @sync_port,
|
||||
'sync_user' => @sync_user,
|
||||
'sync_pwd' => @sync_pwd,
|
||||
'sync_path' => @sync_path,
|
||||
'last_sync' => Time.now.to_i
|
||||
}
|
||||
}
|
||||
|
||||
File.open(@file_config, 'w') do |file|
|
||||
file << config.to_yaml
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
|
||||
return false
|
||||
if /darwin/ =~ RUBY_PLATFORM
|
||||
@config_dir = "#{Dir.home}/Library/Preferences/mpw"
|
||||
elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
|
||||
@config_dir = "#{Dir.home}/AppData/Local/mpw"
|
||||
else
|
||||
@config_dir = "#{Dir.home}/.config/mpw"
|
||||
end
|
||||
|
||||
if @config_file.nil? or @config_file.empty?
|
||||
@config_file = "#{@config_dir}/mpw.cfg"
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new config file
|
||||
# @args: key -> the gpg key to encrypt
|
||||
# lang -> the software language
|
||||
# wallet_dir -> the directory where are the wallets password
|
||||
# @rtrn: true if le config file is create
|
||||
def setup(key, lang, wallet_dir)
|
||||
|
||||
if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
|
||||
@error_msg = I18n.t('error.config.key_bad_format')
|
||||
return false
|
||||
end
|
||||
|
||||
if wallet_dir.empty?
|
||||
wallet_dir = "#{@config_dir}/wallets"
|
||||
end
|
||||
|
||||
config = {'config' => {'key' => key,
|
||||
'lang' => lang,
|
||||
'wallet_dir' => wallet_dir,
|
||||
}
|
||||
}
|
||||
|
||||
Dir.mkdir(wallet_dir, 0700)
|
||||
File.open(@config_file, 'w') do |file|
|
||||
file << config.to_yaml
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Setup a new gpg key
|
||||
# @args: password -> the GPG key password
|
||||
# name -> the name of user
|
||||
# length -> length of the GPG key
|
||||
# expire -> the time of expire to GPG key
|
||||
# @rtrn: true if the GPG key is create, else false
|
||||
def setup_gpg_key(password, name, length = 4096, expire = 0)
|
||||
if name.nil? or name.empty?
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.name')}"
|
||||
return false
|
||||
elsif password.nil? or password.empty?
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.password')}"
|
||||
return false
|
||||
end
|
||||
|
||||
param = ''
|
||||
param << '<GnupgKeyParms format="internal">' + "\n"
|
||||
param << "Key-Type: DSA\n"
|
||||
param << "Key-Length: #{length}\n"
|
||||
param << "Subkey-Type: ELG-E\n"
|
||||
param << "Subkey-Length: #{length}\n"
|
||||
param << "Name-Real: #{name}\n"
|
||||
param << "Name-Comment: #{name}\n"
|
||||
param << "Name-Email: #{@key}\n"
|
||||
param << "Expire-Date: #{expire}\n"
|
||||
param << "Passphrase: #{password}\n"
|
||||
param << "</GnupgKeyParms>\n"
|
||||
|
||||
ctx = GPGME::Ctx.new
|
||||
ctx.genkey(param, nil, nil)
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Check the config file
|
||||
# @rtrn: true if the config file is correct
|
||||
def checkconfig
|
||||
config = YAML::load_file(@config_file)
|
||||
@key = config['config']['key']
|
||||
@lang = config['config']['lang']
|
||||
@wallet_dir = config['config']['wallet_dir']
|
||||
|
||||
if @key.empty? or @wallet_dir.empty?
|
||||
@error_msg = I18n.t('error.config.check')
|
||||
return false
|
||||
end
|
||||
I18n.locale = @lang.to_sym
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.check')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Check if private key exist
|
||||
# @rtrn: true if the key exist, else false
|
||||
def check_gpg_key?
|
||||
ctx = GPGME::Ctx.new
|
||||
ctx.each_key(@key, true) do
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
# Set the last update when there is a sync
|
||||
# @rtrn: true is the file has been updated
|
||||
def set_last_sync
|
||||
config = {'config' => {'key' => @key,
|
||||
'lang' => @lang,
|
||||
'wallet_dir' => @wallet_dir,
|
||||
}
|
||||
}
|
||||
|
||||
File.open(@config_file, 'w') do |file|
|
||||
file << config.to_yaml
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.config.write')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
174
lib/mpw/item.rb
174
lib/mpw/item.rb
|
@ -2,108 +2,104 @@
|
|||
# author: nishiki
|
||||
# mail: nishiki@yaegashi.fr
|
||||
|
||||
require 'rubygems'
|
||||
require 'i18n'
|
||||
|
||||
module MPW
|
||||
class Item
|
||||
class Item
|
||||
|
||||
attr_accessor :error_msg
|
||||
attr_accessor :error_msg
|
||||
|
||||
attr_accessor :id
|
||||
attr_accessor :name
|
||||
attr_accessor :group
|
||||
attr_accessor :host
|
||||
attr_accessor :protocol
|
||||
attr_accessor :user
|
||||
attr_accessor :password
|
||||
attr_accessor :port
|
||||
attr_accessor :comment
|
||||
attr_accessor :last_edit
|
||||
attr_accessor :last_sync
|
||||
attr_accessor :created
|
||||
attr_accessor :id
|
||||
attr_accessor :name
|
||||
attr_accessor :group
|
||||
attr_accessor :host
|
||||
attr_accessor :protocol
|
||||
attr_accessor :user
|
||||
attr_accessor :port
|
||||
attr_accessor :comment
|
||||
attr_accessor :last_edit
|
||||
attr_accessor :last_sync
|
||||
attr_accessor :created
|
||||
|
||||
# Constructor
|
||||
# Create a new item
|
||||
# @args: options -> a hash of parameter
|
||||
# raise an error if the hash hasn't the key name
|
||||
def initialize(options={})
|
||||
if not options.has_key?(:name) or options[:name].to_s.empty?
|
||||
@error_msg = I18n.t('error.update.name_empty')
|
||||
raise @error_msg
|
||||
end
|
||||
|
||||
if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty?
|
||||
@id = generate_id
|
||||
@created = Time.now.to_i
|
||||
else
|
||||
@id = options[:id]
|
||||
@created = options[:created]
|
||||
@last_edit = options[:last_edit]
|
||||
options[:no_update_last_edit] = true
|
||||
end
|
||||
|
||||
update(options)
|
||||
# Constructor
|
||||
# Create a new item
|
||||
# @args: options -> a hash of parameter
|
||||
# raise an error if the hash hasn't the key name
|
||||
def initialize(options={})
|
||||
if not options.has_key?(:name) or options[:name].to_s.empty?
|
||||
@error_msg = I18n.t('error.update.name_empty')
|
||||
raise @error_msg
|
||||
end
|
||||
|
||||
# Update the item
|
||||
# @args: options -> a hash of parameter
|
||||
# @rtrn: true if the item is update
|
||||
def update(options={})
|
||||
if options.has_key?(:name) and options[:name].to_s.empty?
|
||||
@error_msg = I18n.t('error.update.name_empty')
|
||||
return false
|
||||
end
|
||||
|
||||
@name = options[:name] if options.has_key?(:name)
|
||||
@group = options[:group] if options.has_key?(:group)
|
||||
@host = options[:host] if options.has_key?(:host)
|
||||
@protocol = options[:protocol] if options.has_key?(:protocol)
|
||||
@user = options[:user] if options.has_key?(:user)
|
||||
@password = options[:password] if options.has_key?(:password)
|
||||
@port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty?
|
||||
@comment = options[:comment] if options.has_key?(:comment)
|
||||
@last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit)
|
||||
|
||||
return true
|
||||
if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty?
|
||||
@id = generate_id
|
||||
@created = Time.now.to_i
|
||||
else
|
||||
@id = options[:id]
|
||||
@created = options[:created]
|
||||
@last_edit = options[:last_edit]
|
||||
options[:no_update_last_edit] = true
|
||||
end
|
||||
|
||||
# Update last_sync
|
||||
def set_last_sync
|
||||
@last_sync = Time.now.to_i
|
||||
end
|
||||
update(options)
|
||||
end
|
||||
|
||||
# Delete all data
|
||||
# @rtrn: true
|
||||
def delete
|
||||
@id = nil
|
||||
@name = nil
|
||||
@group = nil
|
||||
@host = nil
|
||||
@protocol = nil
|
||||
@user = nil
|
||||
@password = nil
|
||||
@port = nil
|
||||
@comment = nil
|
||||
@created = nil
|
||||
@last_edit = nil
|
||||
@last_sync = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def empty?
|
||||
return @name.to_s.empty?
|
||||
end
|
||||
|
||||
def nil?
|
||||
# Update the item
|
||||
# @args: options -> a hash of parameter
|
||||
# @rtrn: true if the item is update
|
||||
def update(options={})
|
||||
if options.has_key?(:name) and options[:name].to_s.empty?
|
||||
@error_msg = I18n.t('error.update.name_empty')
|
||||
return false
|
||||
end
|
||||
|
||||
# Generate an random id
|
||||
private
|
||||
def generate_id
|
||||
return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join
|
||||
end
|
||||
@name = options[:name] if options.has_key?(:name)
|
||||
@group = options[:group] if options.has_key?(:group)
|
||||
@host = options[:host] if options.has_key?(:host)
|
||||
@protocol = options[:protocol] if options.has_key?(:protocol)
|
||||
@user = options[:user] if options.has_key?(:user)
|
||||
@port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty?
|
||||
@comment = options[:comment] if options.has_key?(:comment)
|
||||
@last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
# Update last_sync
|
||||
def set_last_sync
|
||||
@last_sync = Time.now.to_i
|
||||
end
|
||||
|
||||
# Delete all data
|
||||
# @rtrn: true
|
||||
def delete
|
||||
@id = nil
|
||||
@name = nil
|
||||
@group = nil
|
||||
@host = nil
|
||||
@protocol = nil
|
||||
@user = nil
|
||||
@port = nil
|
||||
@comment = nil
|
||||
@created = nil
|
||||
@last_edit = nil
|
||||
@last_sync = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def empty?
|
||||
return @name.to_s.empty?
|
||||
end
|
||||
|
||||
def nil?
|
||||
return false
|
||||
end
|
||||
|
||||
# Generate an random id
|
||||
private
|
||||
def generate_id
|
||||
return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
569
lib/mpw/mpw.rb
569
lib/mpw/mpw.rb
|
@ -2,331 +2,288 @@
|
|||
# author: nishiki
|
||||
# mail: nishiki@yaegashi.fr
|
||||
|
||||
require 'rubygems'
|
||||
require 'rubygems/package'
|
||||
require 'gpgme'
|
||||
require 'csv'
|
||||
require 'i18n'
|
||||
require 'fileutils'
|
||||
require 'yaml'
|
||||
require 'mpw/item'
|
||||
|
||||
module MPW
|
||||
class MPW
|
||||
|
||||
attr_accessor :error_msg
|
||||
|
||||
# Constructor
|
||||
def initialize(file_gpg, key, share_keys='')
|
||||
@error_msg = nil
|
||||
@file_gpg = file_gpg
|
||||
@key = key
|
||||
@share_keys = share_keys
|
||||
@data = []
|
||||
end
|
||||
|
||||
# Decrypt a gpg file
|
||||
# @args: password -> the GPG key password
|
||||
# @rtrn: true if data has been decrypted
|
||||
def decrypt(password=nil)
|
||||
@data = []
|
||||
class MPW
|
||||
|
||||
if File.exist?(@file_gpg) and not File.zero?(@file_gpg)
|
||||
crypto = GPGME::Crypto.new(armor: true)
|
||||
data_decrypt = crypto.decrypt(IO.read(@file_gpg), password: password).read.force_encoding('utf-8')
|
||||
attr_accessor :error_msg
|
||||
|
||||
# Constructor
|
||||
def initialize(key, wallet_file, gpg_pass=nil)
|
||||
@error_msg = nil
|
||||
@key = key
|
||||
@gpg_pass = gpg_pass
|
||||
@wallet_file = wallet_file
|
||||
end
|
||||
|
||||
if not data_decrypt.to_s.empty?
|
||||
YAML.load(data_decrypt).each_value do |d|
|
||||
@data.push(Item.new(id: d['id'],
|
||||
name: d['name'],
|
||||
group: d['group'],
|
||||
host: d['host'],
|
||||
protocol: d['protocol'],
|
||||
user: d['user'],
|
||||
password: d['password'],
|
||||
port: d['port'],
|
||||
comment: d['comment'],
|
||||
last_edit: d['last_edit'],
|
||||
created: d['created'],
|
||||
)
|
||||
)
|
||||
end
|
||||
# Decrypt a gpg file
|
||||
# @args: password -> the GPG key password
|
||||
# @rtrn: true if data has been decrypted
|
||||
def read_data
|
||||
@config = nil
|
||||
@keys = []
|
||||
@data = []
|
||||
@passwords = {}
|
||||
|
||||
data = nil
|
||||
|
||||
return if not File.exists?(@wallet_file)
|
||||
|
||||
Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar|
|
||||
tar.each do |f|
|
||||
case f.full_name
|
||||
when 'wallet/config.yml'
|
||||
@config = YAML.load(f.read)
|
||||
check_config
|
||||
|
||||
when 'wallet/meta.gpg'
|
||||
data = decrypt(f.read)
|
||||
|
||||
when /^wallet\/keys\/(?<key>.+)\.pub$/
|
||||
@keys[match['key']] = f.read
|
||||
|
||||
when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/
|
||||
@passwords[Regexp.last_match('id')] = f.read
|
||||
else
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.gpg_file.decrypt')}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Encrypt a file
|
||||
# @rtrn: true if the file has been encrypted
|
||||
def encrypt
|
||||
FileUtils.cp(@file_gpg, "#{@file_gpg}.bk") if File.exist?(@file_gpg)
|
||||
|
||||
data_to_encrypt = {}
|
||||
|
||||
@data.each do |item|
|
||||
next if item.empty?
|
||||
|
||||
data_to_encrypt.merge!(item.id => {'id' => item.id,
|
||||
'name' => item.name,
|
||||
'group' => item.group,
|
||||
'host' => item.host,
|
||||
'protocol' => item.protocol,
|
||||
'user' => item.user,
|
||||
'password' => item.password,
|
||||
'port' => item.port,
|
||||
'comment' => item.comment,
|
||||
'last_edit' => item.last_edit,
|
||||
'created' => item.created,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
recipients = []
|
||||
recipients.push(@key)
|
||||
if not @share_keys.nil?
|
||||
@share_keys.split.each { |k| recipients.push(k) }
|
||||
end
|
||||
|
||||
crypto = GPGME::Crypto.new(armor: true)
|
||||
file_gpg = File.open(@file_gpg, 'w+')
|
||||
crypto.encrypt(data_to_encrypt.to_yaml, recipients: recipients, output: file_gpg)
|
||||
file_gpg.close
|
||||
|
||||
FileUtils.rm("#{@file_gpg}.bk") if File.exist?("#{@file_gpg}.bk")
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.gpg_file.encrypt')}\n#{e}"
|
||||
FileUtils.mv("#{@file_gpg}.bk", @file_gpg) if File.exist?("#{@file_gpg}.bk")
|
||||
return false
|
||||
end
|
||||
|
||||
# Add a new item
|
||||
# @args: item -> Object MPW::Item
|
||||
# @rtrn: true if add item
|
||||
def add(item)
|
||||
if not item.instance_of?(Item)
|
||||
@error_msg = I18n.t('error.bad_class')
|
||||
return false
|
||||
elsif item.empty?
|
||||
@error_msg = I18n.t('error.add.empty')
|
||||
return false
|
||||
else
|
||||
@data.push(item)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# Search in some csv data
|
||||
# @args: options -> a hash with paramaters
|
||||
# @rtrn: a list with the resultat of the search
|
||||
def list(options={})
|
||||
result = []
|
||||
|
||||
search = options[:search].to_s.downcase
|
||||
group = options[:group].to_s.downcase
|
||||
protocol = options[:protocol].to_s.downcase
|
||||
if not data.nil? and not data.empty?
|
||||
YAML.load(data).each_value do |d|
|
||||
@data.push(Item.new(id: d['id'],
|
||||
name: d['name'],
|
||||
group: d['group'],
|
||||
host: d['host'],
|
||||
protocol: d['protocol'],
|
||||
user: d['user'],
|
||||
port: d['port'],
|
||||
comment: d['comment'],
|
||||
last_edit: d['last_edit'],
|
||||
created: d['created'],
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@data.each do |item|
|
||||
next if item.empty?
|
||||
# Encrypt a file
|
||||
# @rtrn: true if the file has been encrypted
|
||||
# TODO export key pub
|
||||
def write_data
|
||||
data = {}
|
||||
|
||||
next if not group.empty? and not group.eql?(item.group.downcase)
|
||||
next if not protocol.empty? and not protocol.eql?(item.protocol.downcase)
|
||||
|
||||
name = item.name.to_s.downcase
|
||||
host = item.host.to_s.downcase
|
||||
comment = item.comment.to_s.downcase
|
||||
@data.each do |item|
|
||||
next if item.empty?
|
||||
|
||||
if not name =~ /^.*#{search}.*$/ and not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/
|
||||
next
|
||||
data.merge!(item.id => {'id' => item.id,
|
||||
'name' => item.name,
|
||||
'group' => item.group,
|
||||
'host' => item.host,
|
||||
'protocol' => item.protocol,
|
||||
'user' => item.user,
|
||||
'port' => item.port,
|
||||
'comment' => item.comment,
|
||||
'last_edit' => item.last_edit,
|
||||
'created' => item.created,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
Gem::Package::TarWriter.new(File.open(@wallet_file, 'w+')) do |tar|
|
||||
data_encrypt = encrypt(YAML::dump(data))
|
||||
tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io|
|
||||
io.write(data_encrypt)
|
||||
end
|
||||
|
||||
@passwords.each do |id, password|
|
||||
tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io|
|
||||
io.write(password)
|
||||
end
|
||||
|
||||
result.push(item)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
# Search in some csv data
|
||||
# @args: id -> the id item
|
||||
# @rtrn: a row with the result of the search
|
||||
def search_by_id(id)
|
||||
@data.each do |item|
|
||||
return item if item.id == id
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
# Export to csv
|
||||
# @args: file -> file where you export the data
|
||||
# type -> udata type
|
||||
# @rtrn: true if export work
|
||||
def export(file, type=:yaml)
|
||||
case type
|
||||
when :csv
|
||||
CSV.open(file, 'w', write_headers: true,
|
||||
headers: ['name', 'group', 'protocol', 'host', 'user', 'password', 'port', 'comment']) do |csv|
|
||||
@data.each do |item|
|
||||
csv << [item.name, item.group, item.protocol, item.host, item.user, item.password, item.port, item.comment]
|
||||
end
|
||||
end
|
||||
|
||||
when :yaml
|
||||
data = {}
|
||||
@data.each do |item|
|
||||
data.merge!(item.id => {'id' => item.id,
|
||||
'name' => item.name,
|
||||
'group' => item.group,
|
||||
'host' => item.host,
|
||||
'protocol' => item.protocol,
|
||||
'user' => item.user,
|
||||
'password' => item.password,
|
||||
'port' => item.port,
|
||||
'comment' => item.comment,
|
||||
'last_edit' => item.last_edit,
|
||||
'created' => item.created,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
File.open(file, 'w') {|f| f << data.to_yaml}
|
||||
|
||||
else
|
||||
@error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.export.write', file: file)}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Import to csv
|
||||
# @args: file -> path to file import
|
||||
# type -> udata type
|
||||
# @rtrn: true if the import work
|
||||
def import(file, type=:yaml)
|
||||
case type
|
||||
when :csv
|
||||
CSV.foreach(file, {headers: true}) do |row|
|
||||
item = Item.new(name: row['name'],
|
||||
group: row['group'],
|
||||
host: row['host'],
|
||||
protocol: row['protocol'],
|
||||
user: row['user'],
|
||||
password: row['password'],
|
||||
port: row['port'],
|
||||
comment: row['comment'],
|
||||
)
|
||||
|
||||
return false if item.empty?
|
||||
|
||||
@data.push(item)
|
||||
end
|
||||
|
||||
when :yaml
|
||||
YAML::load_file(file).each_value do |row|
|
||||
item = Item.new(name: row['name'],
|
||||
group: row['group'],
|
||||
host: row['host'],
|
||||
protocol: row['protocol'],
|
||||
user: row['user'],
|
||||
password: row['password'],
|
||||
port: row['port'],
|
||||
comment: row['comment'],
|
||||
)
|
||||
|
||||
return false if item.empty?
|
||||
|
||||
@data.push(item)
|
||||
end
|
||||
|
||||
else
|
||||
@error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.import.read', file: file)}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Return a preview import
|
||||
# @args: file -> path to file import
|
||||
# @rtrn: a hash with the items to import, if there is an error return false
|
||||
def import_preview(file, type=:yaml)
|
||||
data = []
|
||||
|
||||
case type
|
||||
when :csv
|
||||
CSV.foreach(file, {headers: true}) do |row|
|
||||
item = Item.new(name: row['name'],
|
||||
group: row['group'],
|
||||
host: row['host'],
|
||||
protocol: row['protocol'],
|
||||
user: row['user'],
|
||||
password: row['password'],
|
||||
port: row['port'],
|
||||
comment: row['comment'],
|
||||
)
|
||||
|
||||
return false if item.empty?
|
||||
|
||||
data.push(item)
|
||||
end
|
||||
|
||||
when :yaml
|
||||
YAML::load_file(file).each_value do |row|
|
||||
item = Item.new(name: row['name'],
|
||||
group: row['group'],
|
||||
host: row['host'],
|
||||
protocol: row['protocol'],
|
||||
user: row['user'],
|
||||
password: row['password'],
|
||||
port: row['port'],
|
||||
comment: row['comment'],
|
||||
)
|
||||
|
||||
return false if item.empty?
|
||||
|
||||
data.push(item)
|
||||
end
|
||||
|
||||
else
|
||||
@error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
|
||||
return false
|
||||
end
|
||||
|
||||
return data
|
||||
rescue Exception => e
|
||||
@error_msg = "#{I18n.t('error.import.read', file: file)}\n#{e}"
|
||||
return false
|
||||
end
|
||||
|
||||
# Generate a random password
|
||||
# @args: length -> the length password
|
||||
# @rtrn: a random string
|
||||
def self.password(length=8)
|
||||
if length.to_i <= 0
|
||||
length = 8
|
||||
else
|
||||
length = length.to_i
|
||||
end
|
||||
|
||||
result = ''
|
||||
while length > 62 do
|
||||
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(62).join
|
||||
length -= 62
|
||||
end
|
||||
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# TODO comment
|
||||
def get_password(id)
|
||||
return decrypt(@passwords[id])
|
||||
end
|
||||
|
||||
# TODO comment
|
||||
def set_password(id, password)
|
||||
@passwords[id] = encrypt(password)
|
||||
end
|
||||
|
||||
# TODO
|
||||
def check_config
|
||||
if false
|
||||
raise 'ERROR'
|
||||
end
|
||||
end
|
||||
|
||||
# Add a new item
|
||||
# @args: item -> Object MPW::Item
|
||||
# @rtrn: true if add item
|
||||
# TODO add password
|
||||
def add(item)
|
||||
if not item.instance_of?(Item)
|
||||
raise I18n.t('error.bad_class')
|
||||
elsif item.empty?
|
||||
raise I18n.t('error.add.empty')
|
||||
else
|
||||
@data.push(item)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Search in some csv data
|
||||
# @args: options -> a hash with paramaters
|
||||
# @rtrn: a list with the resultat of the search
|
||||
def list(options={})
|
||||
result = []
|
||||
|
||||
search = options[:search].to_s.downcase
|
||||
group = options[:group].to_s.downcase
|
||||
protocol = options[:protocol].to_s.downcase
|
||||
|
||||
@data.each do |item|
|
||||
next if item.empty?
|
||||
|
||||
next if not group.empty? and not group.eql?(item.group.downcase)
|
||||
next if not protocol.empty? and not protocol.eql?(item.protocol.downcase)
|
||||
|
||||
name = item.name.to_s.downcase
|
||||
host = item.host.to_s.downcase
|
||||
comment = item.comment.to_s.downcase
|
||||
|
||||
if not name =~ /^.*#{search}.*$/ and not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/
|
||||
next
|
||||
end
|
||||
|
||||
result.push(item)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
# Search in some csv data
|
||||
# @args: id -> the id item
|
||||
# @rtrn: a row with the result of the search
|
||||
def search_by_id(id)
|
||||
@data.each do |item|
|
||||
return item if item.id == id
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
# Export to csv
|
||||
# @args: file -> file where you export the data
|
||||
def export(file)
|
||||
data = {}
|
||||
@data.each do |item|
|
||||
data.merge!(item.id => {'id' => item.id,
|
||||
'name' => item.name,
|
||||
'group' => item.group,
|
||||
'host' => item.host,
|
||||
'protocol' => item.protocol,
|
||||
'user' => item.user,
|
||||
'password' => get_password(item.id),
|
||||
'port' => item.port,
|
||||
'comment' => item.comment,
|
||||
'last_edit' => item.last_edit,
|
||||
'created' => item.created,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
File.open(file, 'w') {|f| f << data.to_yaml}
|
||||
rescue Exception => e
|
||||
raise "#{I18n.t('error.export.write', file: file)}\n#{e}"
|
||||
end
|
||||
|
||||
# Import to yaml
|
||||
# @args: file -> path to file import
|
||||
# TODO raise
|
||||
def import(file)
|
||||
YAML::load_file(file).each_value do |row|
|
||||
item = Item.new(name: row['name'],
|
||||
group: row['group'],
|
||||
host: row['host'],
|
||||
protocol: row['protocol'],
|
||||
user: row['user'],
|
||||
port: row['port'],
|
||||
comment: row['comment'],
|
||||
)
|
||||
|
||||
raise 'Item is empty' if item.empty?
|
||||
|
||||
@data.push(item)
|
||||
set_password(item.id, row['password'])
|
||||
end
|
||||
rescue Exception => e
|
||||
raise "#{I18n.t('error.import.read', file: file)}\n#{e}"
|
||||
end
|
||||
|
||||
# Generate a random password
|
||||
# @args: length -> the length password
|
||||
# @rtrn: a random string
|
||||
def self.password(length=8)
|
||||
if length.to_i <= 0
|
||||
length = 8
|
||||
else
|
||||
length = length.to_i
|
||||
end
|
||||
|
||||
result = ''
|
||||
while length > 62 do
|
||||
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(62).join
|
||||
length -= 62
|
||||
end
|
||||
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
# Decrypt a gpg file
|
||||
# @args: password -> the GPG key password
|
||||
# @rtrn: true if data has been decrypted
|
||||
private
|
||||
def decrypt(data)
|
||||
crypto = GPGME::Crypto.new(armor: true)
|
||||
|
||||
return crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8')
|
||||
rescue Exception => e
|
||||
raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}"
|
||||
end
|
||||
|
||||
# Encrypt a file
|
||||
# @rtrn: true if the file has been encrypted
|
||||
private
|
||||
def encrypt(data)
|
||||
recipients = []
|
||||
crypto = GPGME::Crypto.new(armor: true)
|
||||
|
||||
# @config['keys'].each do |key|
|
||||
# recipients.push(key)
|
||||
# end
|
||||
|
||||
recipients.push(@key)
|
||||
|
||||
return crypto.encrypt(data, recipients: recipients).read
|
||||
rescue Exception => e
|
||||
raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
#!/usr/bin/ruby
|
||||
# author: nishiki
|
||||
# mail: nishiki@yaegashi.fr
|
||||
# info: a simple script who m your passwords
|
||||
|
||||
require 'rubygems'
|
||||
require 'highline/import'
|
||||
require 'pathname'
|
||||
require 'readline'
|
||||
require 'i18n'
|
||||
require 'colorize'
|
||||
require 'mpw/sync'
|
||||
require 'highline/import'
|
||||
require 'mpw/mpw'
|
||||
require 'mpw/item'
|
||||
|
||||
|
@ -18,29 +14,10 @@ class Cli
|
|||
# Constructor
|
||||
# @args: lang -> the operating system language
|
||||
# config_file -> a specify config file
|
||||
# TODO
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
# Sync the data with the server
|
||||
# @args: allow_sync -> allow or disable sync (boolean)
|
||||
# @rtnr: true if the synchro is finish
|
||||
def sync(allow_sync=nil)
|
||||
if not allow_sync.nil?
|
||||
@allow_sync = allow_sync
|
||||
end
|
||||
|
||||
return true if not @allow_sync
|
||||
|
||||
@sync = MPW::Sync.new(@config, @mpw, @password)
|
||||
|
||||
raise(@sync.error_msg) if not @sync.get_remote
|
||||
raise(@sync.error_msg) if not @sync.sync
|
||||
|
||||
return true
|
||||
rescue Exception => e
|
||||
puts "#{I18n.t('display.error')} #7: #{e}".red
|
||||
return false
|
||||
@wallet_file = "#{@config.wallet_dir}/test.mpw"
|
||||
end
|
||||
|
||||
# Create a new config file
|
||||
|
@ -48,33 +25,16 @@ class Cli
|
|||
def setup(lang)
|
||||
puts I18n.t('form.setup.title')
|
||||
puts '--------------------'
|
||||
language = ask(I18n.t('form.setup.lang', lang: lang)).to_s
|
||||
key = ask(I18n.t('form.setup.gpg_key')).to_s
|
||||
share_keys = ask(I18n.t('form.setup.share_gpg_keys')).to_s
|
||||
file_gpg = ask(I18n.t('form.setup.gpg_file', home: @conf.dir_config)).to_s
|
||||
sync_type = ask(I18n.t('form.setup.sync_type')).to_s
|
||||
language = ask(I18n.t('form.setup.lang', lang: lang)).to_s
|
||||
key = ask(I18n.t('form.setup.gpg_key')).to_s
|
||||
wallet_dir = ask(I18n.t('form.setup.wallet_dir')).to_s
|
||||
|
||||
if ['ssh', 'ftp', 'mpw'].include?(sync_type)
|
||||
sync_host = ask(I18n.t('form.setup.sync_host')).to_s
|
||||
sync_port = ask(I18n.t('form.setup.sync_port')).to_s
|
||||
sync_user = ask(I18n.t('form.setup.sync_user')).to_s
|
||||
sync_pwd = ask(I18n.t('form.setup.sync_pwd')).to_s
|
||||
sync_path = ask(I18n.t('form.setup.sync_path')).to_s
|
||||
end
|
||||
|
||||
if language.nil? or language.empty?
|
||||
language = lang
|
||||
end
|
||||
I18n.locale = language.to_sym
|
||||
|
||||
sync_type = sync_type.nil? or sync_type.empty? ? nil : sync_type
|
||||
sync_host = sync_host.nil? or sync_host.empty? ? nil : sync_host
|
||||
sync_port = sync_port.nil? or sync_port.empty? ? nil : sync_port.to_i
|
||||
sync_user = sync_user.nil? or sync_user.empty? ? nil : sync_user
|
||||
sync_pwd = sync_pwd.nil? or sync_pwd.empty? ? nil : sync_pwd
|
||||
sync_path = sync_path.nil? or sync_path.empty? ? nil : sync_path
|
||||
|
||||
if @config.setup(key, share_keys, language, file_gpg, sync_type, sync_host, sync_port, sync_user, sync_pwd, sync_path)
|
||||
if @config.setup(key, lang, wallet_dir)
|
||||
puts "#{I18n.t('form.setup.valid')}".green
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #8: #{@config.error_msg}".red
|
||||
|
@ -86,7 +46,7 @@ class Cli
|
|||
exit 2
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Setup a new GPG key
|
||||
def setup_gpg_key
|
||||
puts I18n.t('form.setup_gpg_key.title')
|
||||
|
@ -124,17 +84,15 @@ class Cli
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# Request the GPG password and decrypt the file
|
||||
def decrypt
|
||||
if not defined?(@mpw)
|
||||
@mpw = MPW::MPW.new(@config.file_gpg, @config.key, @config.share_keys)
|
||||
@password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false}
|
||||
@mpw = MPW::MPW.new(@config.key, @wallet_file, @password)
|
||||
end
|
||||
|
||||
@password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false}
|
||||
if not @mpw.decrypt(@password)
|
||||
puts "#{I18n.t('display.error')} #11: #{@mpw.error_msg}".red
|
||||
exit 2
|
||||
end
|
||||
@mpw.read_data
|
||||
end
|
||||
|
||||
# Display the query's result
|
||||
|
@ -185,7 +143,7 @@ class Cli
|
|||
print "#{I18n.t('display.login')}: ".cyan
|
||||
puts item.user
|
||||
print "#{I18n.t('display.password')}: ".cyan
|
||||
puts item.password
|
||||
puts @mpw.get_password(item.id)
|
||||
print "#{I18n.t('display.port')}: ".cyan
|
||||
puts item.port
|
||||
print "#{I18n.t('display.comment')}: ".cyan
|
||||
|
@ -203,21 +161,17 @@ class Cli
|
|||
options[:host] = ask(I18n.t('form.add.server')).to_s
|
||||
options[:protocol] = ask(I18n.t('form.add.protocol')).to_s
|
||||
options[:user] = ask(I18n.t('form.add.login')).to_s
|
||||
options[:password] = ask(I18n.t('form.add.password')).to_s
|
||||
password = ask(I18n.t('form.add.password')).to_s
|
||||
options[:port] = ask(I18n.t('form.add.port')).to_s
|
||||
options[:comment] = ask(I18n.t('form.add.comment')).to_s
|
||||
|
||||
item = MPW::Item.new(options)
|
||||
if @mpw.add(item)
|
||||
if @mpw.encrypt
|
||||
sync
|
||||
puts "#{I18n.t('form.add.valid')}".green
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #12: #{@mpw.error_msg}".red
|
||||
end
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #13: #{item.error_msg}".red
|
||||
end
|
||||
|
||||
@mpw.add(item)
|
||||
@mpw.set_password(item.id, password)
|
||||
@mpw.write_data
|
||||
|
||||
puts "#{I18n.t('form.add.valid')}".green
|
||||
end
|
||||
|
||||
# Update an item
|
||||
|
@ -235,22 +189,17 @@ class Cli
|
|||
options[:host] = ask(I18n.t('form.update.server' , server: item.host)).to_s
|
||||
options[:protocol] = ask(I18n.t('form.update.protocol', protocol: item.protocol)).to_s
|
||||
options[:user] = ask(I18n.t('form.update.login' , login: item.user)).to_s
|
||||
options[:password] = ask(I18n.t('form.update.password')).to_s
|
||||
password = ask(I18n.t('form.update.password')).to_s
|
||||
options[:port] = ask(I18n.t('form.update.port' , port: item.port)).to_s
|
||||
options[:comment] = ask(I18n.t('form.update.comment' , comment: item.comment)).to_s
|
||||
|
||||
options.delete_if { |k,v| v.empty? }
|
||||
|
||||
if item.update(options)
|
||||
if @mpw.encrypt
|
||||
sync
|
||||
puts "#{I18n.t('form.update.valid')}".green
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #14: #{@mpw.error_msg}".red
|
||||
end
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #15: #{item.error_msg}".red
|
||||
end
|
||||
item.update(options)
|
||||
@mpw.encrypt
|
||||
@mpw.write_data
|
||||
|
||||
puts "#{I18n.t('form.update.valid')}".green
|
||||
else
|
||||
puts I18n.t('display.nothing')
|
||||
end
|
||||
|
@ -289,43 +238,22 @@ class Cli
|
|||
|
||||
# Export the items in a CSV file
|
||||
# @args: file -> the destination file
|
||||
def export(file, type=:yaml)
|
||||
if @mpw.export(file, type)
|
||||
puts "#{I18n.t('export.valid', file)}".green
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #17: #{@mpw.error_msg}".red
|
||||
end
|
||||
def export(file)
|
||||
@mpw.export(file)
|
||||
|
||||
puts "#{I18n.t('export.valid', file)}".green
|
||||
rescue Exception => e
|
||||
puts "#{I18n.t('display.error')} #17: #{e}".red
|
||||
end
|
||||
|
||||
# Import items from a CSV file
|
||||
# Import items from a YAML file
|
||||
# @args: file -> the import file
|
||||
# force -> no resquest a validation
|
||||
def import(file, type=:yaml, force=false)
|
||||
def import(file)
|
||||
@mpw.import(file)
|
||||
@mpw.write_data
|
||||
|
||||
if not force
|
||||
result = @mpw.import_preview(file, type)
|
||||
if result.is_a?(Array) and not result.empty?
|
||||
result.each do |r|
|
||||
display_item(r)
|
||||
end
|
||||
|
||||
confirm = ask("#{I18n.t('form.import.ask', file: file)} (y/N) ").to_s
|
||||
if confirm =~ /^(y|yes|YES|Yes|Y)$/
|
||||
force = true
|
||||
end
|
||||
else
|
||||
puts I18n.t('form.import.not_valid')
|
||||
end
|
||||
end
|
||||
|
||||
if force
|
||||
if @mpw.import(file, type) and @mpw.encrypt
|
||||
sync
|
||||
puts "#{I18n.t('form.import.valid')}".green
|
||||
else
|
||||
puts "#{I18n.t('display.error')} #18: #{@mpw.error_msg}".red
|
||||
end
|
||||
end
|
||||
puts "#{I18n.t('form.import.valid')}".green
|
||||
rescue Exception => e
|
||||
puts "#{I18n.t('display.error')} #18: #{e}".red
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue