diff --git a/MPW/Config.rb b/MPW/Config.rb index 74d309c..92a58fd 100644 --- a/MPW/Config.rb +++ b/MPW/Config.rb @@ -18,10 +18,12 @@ module MPW attr_accessor :file_gpg attr_accessor :timeout_pwd 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_suffix + attr_accessor :sync_path attr_accessor :last_update # Constructor @@ -40,12 +42,14 @@ module MPW # lang -> the software language # file_gpg -> the file who is encrypted # timeout_pwd -> time to save the password + # 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, lang, file_gpg, timeout_pwd, sync_host=nil, sync_port=nil, sync_pwd=nil, sync_suffix=nil) + def setup(key, lang, file_gpg, timeout_pwd, sync_type=nil, sync_host=nil, sync_port=nil, sync_user=nil, sync_pwd=nil, sync_path=nil) if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ @error_msg = I18n.t('error.config.key_bad_format') @@ -62,77 +66,76 @@ module MPW 'lang' => lang, 'file_gpg' => file_gpg, 'timeout_pwd' => timeout_pwd, + 'sync_type' => sync_type, 'sync_host' => sync_host, 'sync_port' => sync_port, + 'sync_user' => sync_user, 'sync_pwd' => sync_pwd, - 'sync_suffix' => sync_suffix, + 'sync_path' => sync_path, 'last_update' => 0 }} - begin - File.open(@file_config, 'w') do |file| - file << config.to_yaml - end - rescue Exception => e - @error_msg = "#{I18n.t('error.config.write')}\n#{e}" - return false + 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 # Check the config file # @rtrn: true if the config file is correct def checkconfig() - begin - config = YAML::load_file(@file_config) - @key = config['config']['key'] - @lang = config['config']['lang'] - @file_gpg = config['config']['file_gpg'] - @timeout_pwd = config['config']['timeout_pwd'].to_i - @sync_host = config['config']['sync_host'] - @sync_port = config['config']['sync_port'] - @sync_pwd = config['config']['sync_pwd'] - @sync_suffix = config['config']['sync_suffix'] - @last_update = config['config']['last_update'].to_i - - if @key.empty? || @file_gpg.empty? - @error_msg = I18n.t('error.config.check') - return false - end - - I18n.locale = @lang.to_sym - - rescue Exception => e - @error_msg = "#{I18n.t('error.config.check')}\n#{e}" + config = YAML::load_file(@file_config) + @key = config['config']['key'] + @lang = config['config']['lang'] + @file_gpg = config['config']['file_gpg'] + @timeout_pwd = config['config']['timeout_pwd'].to_i + @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_update = config['config']['last_update'].to_i + + if @key.empty? || @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 # Set the last update when there is a sync # @rtrn: true is the file has been updated - def set_last_update() + def set_last_update config = {'config' => {'key' => @key, 'lang' => @lang, 'file_gpg' => @file_gpg, 'timeout_pwd' => @timeout_pwd, + 'sync_type' => @sync_type, 'sync_host' => @sync_host, 'sync_port' => @sync_port, + 'sync_user' => @sync_user, 'sync_pwd' => @sync_pwd, - 'sync_suffix' => @sync_suffix, + 'sync_path' => @sync_path, 'last_update' => Time.now.to_i }} - begin - File.open(@file_config, 'w') do |file| - file << config.to_yaml - end - rescue Exception => e - @error_msg = "#{I18n.t('error.config.write')}\n#{e}" - return false + 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 end diff --git a/MPW/MPW.rb b/MPW/MPW.rb index 1f84400..c57b696 100644 --- a/MPW/MPW.rb +++ b/MPW/MPW.rb @@ -36,45 +36,41 @@ module MPW # @args: password -> the GPG key password # @rtrn: true if data has been decrypted def decrypt(passwd=nil) - @data = Array.new + @data = [] - begin - if File.exist?(@file_gpg) - crypto = GPGME::Crypto.new(:armor => true) - data_decrypt = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read + if File.exist?(@file_gpg) + crypto = GPGME::Crypto.new(:armor => true) + data_decrypt = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read - data_decrypt.lines do |line| - @data.push(line.parse_csv) - end + data_decrypt.lines do |line| + @data.push(line.parse_csv) end - - return true - rescue Exception => e - @error_msg = "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" - return false 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() - begin - crypto = GPGME::Crypto.new(:armor => true) - file_gpg = File.open(@file_gpg, 'w+') + def encrypt + crypto = GPGME::Crypto.new(:armor => true) + file_gpg = File.open(@file_gpg, 'w+') - data_to_encrypt = '' - @data.each do |row| - data_to_encrypt << row.to_csv - end - - crypto.encrypt(data_to_encrypt, :recipients => @key, :output => file_gpg) - file_gpg.close - - return true - rescue Exception => e - @error_msg = "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" - return false + data_to_encrypt = '' + @data.each do |row| + data_to_encrypt << row.to_csv end + + crypto.encrypt(data_to_encrypt, :recipients => @key, :output => file_gpg) + file_gpg.close + + return true + rescue Exception => e + @error_msg = "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" + return false end # Search in some csv data @@ -159,13 +155,13 @@ module MPW row_update[PORT] = port.nil? || port.empty? ? row[PORT] : port row_update[COMMENT] = comment.nil? || comment.empty? ? row[COMMENT] : comment - row_update[] = row_update[NAME].nil? ? nil : row_update[NAME].force_encoding('ASCII-8BIT') - row_update[] = row_update[GROUP].nil? ? nil : row_update[GROUP].force_encoding('ASCII-8BIT') - row_update[] = row_update[SERVER].nil? ? nil : row_update[SERVER].force_encoding('ASCII-8BIT') - row_update[] = row_update[PROTOCOL].nil? ? nil : row_update[PROTOCOL].force_encoding('ASCII-8BIT') - row_update[] = row_update[LOGIN].nil? ? nil : row_update[LOGIN].force_encoding('ASCII-8BIT') - row_update[] = row_update[PASSWORD].nil? ? nil : row_update[PASSWORD].force_encoding('ASCII-8BIT') - row_update[] = row_update[COMMENT].nil? ? nil : row_update[COMMENT].force_encoding('ASCII-8BIT') + row_update[NAME] = row_update[NAME].nil? ? nil : row_update[NAME].force_encoding('ASCII-8BIT') + row_update[GROUP] = row_update[GROUP].nil? ? nil : row_update[GROUP].force_encoding('ASCII-8BIT') + row_update[SERVER] = row_update[SERVER].nil? ? nil : row_update[SERVER].force_encoding('ASCII-8BIT') + row_update[PROTOCOL] = row_update[PROTOCOL].nil? ? nil : row_update[PROTOCOL].force_encoding('ASCII-8BIT') + row_update[LOGIN] = row_update[LOGIN].nil? ? nil : row_update[LOGIN].force_encoding('ASCII-8BIT') + row_update[PASSWORD] = row_update[PASSWORD].nil? ? nil : row_update[PASSWORD].force_encoding('ASCII-8BIT') + row_update[COMMENT] = row_update[COMMENT].nil? ? nil : row_update[COMMENT].force_encoding('ASCII-8BIT') if row_update[NAME].nil? || row_update[NAME].empty? @error_msg = I18n.t('error.update.name_empty') @@ -202,71 +198,65 @@ module MPW # @args: file -> a string to match # @rtrn: true if export work def export(file) - begin - File.open(file, 'w+') do |file| - @data.each do |row| - row.delete_at(ID).delete_at(DATE) - file << row.to_csv - end + File.open(file, 'w+') do |file| + @data.each do |row| + row.delete_at(ID).delete_at(DATE) + file << row.to_csv end - - return true - rescue Exception => e - @error_msg = "#{I18n.t('error.export.write', :file => file)}\n#{e}" - 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 # @rtrn: true if the import work def import(file) - begin - data_new = IO.read(file) - data_new.lines do |line| - if not line =~ /(.*,){6}/ - @error_msg = I18n.t('error.import.bad_format') + data_new = IO.read(file) + data_new.lines do |line| + if not line =~ /(.*,){6}/ + @error_msg = I18n.t('error.import.bad_format') + return false + else + row = line.parse_csv.unshift(0) + if not update(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT]) return false - else - row = line.parse_csv.unshift(0) - if not update(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT]) - return false - end end end - - return true - rescue Exception => e - @error_msg = "#{I18n.t('error.import.read', :file => file)}\n#{e}" - 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: an array with the items to import, if there is an error return false def import_preview(file) - begin - result = Array.new() - id = 0 - - data = IO.read(file) - data.lines do |line| - if not line =~ /(.*,){6}/ - @error_msg = I18n.t('error.import.bad_format') - return false - else - result.push(line.parse_csv.unshift(id)) - end - - id += 1 + result = Array.new() + id = 0 + + data = IO.read(file) + data.lines do |line| + if not line =~ /(.*,){6}/ + @error_msg = I18n.t('error.import.bad_format') + return false + else + result.push(line.parse_csv.unshift(id)) end - - return result - rescue Exception => e - @error_msg = "#{I18n.t('error.import.read', :file => file)}\n#{e}" - return false + + id += 1 end + + return result + rescue Exception => e + @error_msg = "#{I18n.t('error.import.read', :file => file)}\n#{e}" + return false end # Sync remote data and local data @@ -308,7 +298,7 @@ module MPW end end - return encrypt() + return encrypt end # Generate a random password diff --git a/MPW/Sync/MPW.rb b/MPW/Sync/MPW.rb index 14a43c5..d0462a8 100644 --- a/MPW/Sync/MPW.rb +++ b/MPW/Sync/MPW.rb @@ -12,7 +12,7 @@ module MPW require 'socket' require 'json' - class MPW + class MPWSync attr_accessor :error_msg attr_accessor :enable @@ -30,12 +30,12 @@ module MPW # password -> the remote password # suffix -> the suffix file # @rtrn: false if the connection fail - def connect(host, port, gpg_key, password, suffix=nil) - @gpg_key = gpg_key + def connect(host, user, password, path, port=nil) + @gpg_key = user @password = password - @suffix = suffix + @suffix = path - @socket = TCPSocket.new(host, port) + @socket = TCPSocket.new(host, port.to_i) @enable = true rescue Exception => e @error_msg = "#{I18n.t('error.sync.connection')}\n#{e}" @@ -64,24 +64,23 @@ module MPW @error_msg = I18n.t('error.sync.communication') return nil elsif msg['error'].nil? - tmp_file = "/tmp/mpw-#{MPW.password()}.gpg" + tmp_file = tmpfile File.open(tmp_file, 'w') do |file| file << msg['data'] end - @mpw = MPW.new(tmp_file) - if !@mpw.decrypt(gpg_password) - puts @mpw.error_msg + mpw = MPW.new(tmp_file) + if !mpw.decrypt(gpg_password) + @error_msg = mpw.error_msg return nil end - + File.unlink(tmp_file) - return @mpw.search() + return mpw.search else @error_msg = I18n.t(msg['error']) return nil end - end # Update the remote data @@ -121,6 +120,16 @@ module MPW send_msg = {:action => 'close'} @socket.puts send_msg.to_json end + + # Generate a random string + # @rtrn: a random string + def tmpfile + result = '' + result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(6).join + + return "/tmp/mpw-#{result}" + end + end end diff --git a/MPW/Sync/SSH.rb b/MPW/Sync/SSH.rb index b63d912..bd92fc6 100644 --- a/MPW/Sync/SSH.rb +++ b/MPW/Sync/SSH.rb @@ -41,7 +41,6 @@ module MPW @error_msg = "#{I18n.t('error.sync.connection')}\n#{e}" @enable = false else - return @enable end @@ -53,7 +52,7 @@ module MPW return nil end - tmp_file = "/tmp/mpw-#{MPW.password()}.gpg" + tmp_file = tmpfile Net::SCP.start(@host, @user, :password => @password, :port => @port) do |ssh| ssh.scp.download(@path, tmp_file) end @@ -62,15 +61,14 @@ module MPW file << msg['data'] end - @mpw = MPW.new(tmp_file) - if !@mpw.decrypt(gpg_password) - puts @mpw.error_msg + mpw = MPW.new(tmp_file) + if !mpw.decrypt(gpg_password) + @error_msg = mpw.error_msg return nil end File.unlink(tmp_file) - - return @mpw.search() + return mpw.search rescue Exception => e @error_msg = "#{I18n.t('error.sync.download')}\n#{e}" return nil @@ -84,7 +82,7 @@ module MPW return true end - tmp_file = "/tmp/mpw-#{MPW.password()}.gpg" + tmp_file = tmpfile Net::SCP.start(@host, @user, :password => @password, :port => @port) do |ssh| ssh.scp.upload(tmp_file, @path) end @@ -100,6 +98,16 @@ module MPW # Close the connection def close end + + # Generate a random string + # @rtrn: a random string + def tmpfile + result = '' + result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(6).join + + return "/tmp/mpw-#{result}" + end + end end diff --git a/MPW/UI/Cli.rb b/MPW/UI/Cli.rb index 870c9a2..1b0ce0b 100644 --- a/MPW/UI/Cli.rb +++ b/MPW/UI/Cli.rb @@ -23,39 +23,44 @@ class Cli end # Close sync - def sync_close() - @sync.close() + def sync_close + @sync.close end # Sync the data with the server # @rtnr: true if the synchro is finish - def sync() + def sync if !defined?(@sync) - @sync = MPW::Sync::MPW.new - - if !@config.sync_host.nil? && !@config.sync_port.nil? - if !@sync.connect(@config.sync_host, @config.sync_port, @config.key, @config.sync_pwd, @config.sync_suffix) - puts "#{I18n.t('display.error')}: #{@sync.error_msg}" - end + case @config.sync_type + when 'mpw' + @sync = MPW::Sync::MPWSync.new + when 'sftp', 'scp', 'ssh' + @sync = MPW::Sync::SSH.new + else + return false end end - begin - if @sync.enable - if !@mpw.sync(@sync.get(@passwd), @config.last_update) - puts "#{I18n.t('display.error')}: #{@mpw.error_msg}" - elsif !@sync.update(File.open(@config.file_gpg).read) - puts "#{I18n.t('display.error')}: #{@sync.error_msg}" - elsif !@config.set_last_update() - puts "#{I18n.t('display.error')}: #{@config.error_msg}" - else - return true - end + if !@config.sync_host.nil? && !@config.sync_port.nil? + if !@sync.connect(@config.sync_host, @config.sync_user, @config.sync_pwd, @config.sync_path, @config.sync_port) + puts "#{I18n.t('display.error')}: #{@sync.error_msg}" end - rescue Exception => e - puts "#{I18n.t('display.error')}: #{e}" end + if @sync.enable + if !@mpw.sync(@sync.get(@passwd), @config.last_update) + puts "#{I18n.t('display.error')}: #{@sync.error_msg}" + elsif !@sync.update(File.open(@config.file_gpg).read) + puts "#{I18n.t('display.error')}: #{@sync.error_msg}" + elsif !@config.set_last_update + puts "#{I18n.t('display.error')}: #{@config.error_msg}" + else + return true + end + end + rescue Exception => e + puts "#{I18n.t('display.error')}: #{e}" + else return false end @@ -96,7 +101,7 @@ class Cli end # Request the GPG password and decrypt the file - def decrypt() + def decrypt if !defined?(@mpw) @mpw = MPW::MPW.new(@config.file_gpg, @config.key) end