From 4aa959d59125684109ffab85761522f97f2e723d Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 17:55:05 +0100 Subject: [PATCH 01/27] MPW server, get and update a gpg file --- lib/Server.rb | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++ mpw-server | 46 +++++++++ 2 files changed, 301 insertions(+) create mode 100644 lib/Server.rb create mode 100755 mpw-server diff --git a/lib/Server.rb b/lib/Server.rb new file mode 100644 index 0000000..77e4415 --- /dev/null +++ b/lib/Server.rb @@ -0,0 +1,255 @@ +#!/usr/bin/ruby + +require 'socket' +require 'json' +require 'highline/import' +require 'digest' +require 'base64' + +require "#{APP_ROOT}/lib/MPW.rb" + +class Server + + attr_accessor :error_msg + + # Constructor + def initialize() + YAML::ENGINE.yamler='syck' + @error_msg = nil + end + + # Start the server + def start() + server = TCPServer.open(@host, @port) + loop do + Thread.start(server.accept) do |client| + msg = self.getClientMessage(client) + + if !msg + next + end + + if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty? + self.closeConnection(client) + next + end + + case msg['action'] + when 'get' + client.puts self.getFile(msg) + when 'update' + client.puts self.updateFile(msg) + when 'delete' + client.puts self.deleteFile(msg) + else + client.puts 'Unknown command' + end + + self.closeConnection(client) + end + end + end + + # Get a gpg file + # @args: msg -> message puts by the client + # @rtrn: json message + def getFile(msg) + gpg_key = msg['gpg_key'].sub('@', '_') + + if msg['suffix'].nil? || msg['suffix'].empty? + file_gpg = "#{@data_dir}/#{gpg_key}.yml" + else + file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml" + end + + if File.exist?(file_gpg) + gpg_data = YAML::load_file(file_gpg) + salt = gpg_data['gpg']['salt'] + hash = gpg_data['gpg']['hash'] + data = gpg_data['gpg']['data'] + + if self.isAuthorized?(msg['password'], salt, hash) + send_msg = {:action => 'get', + :gpg_key => msg['gpg_key'], + :msg => 'get_done', + :data => data} + else + send_msg = {:action => 'get', + :gpg_key => msg['gpg_key'], + :msg => 'get_fail', + :error => 'not_authorized'} + end + else + send_msg = {:action => 'get', + :gpg_key => msg['gpg_key'], + :msg => 'get_fail', + :error => 'file_not_exist'} + end + + return send_msg.to_json + end + + # Update a file + # @args: msg -> message puts by the client + # @rtrn: json message + def updateFile(msg) + begin + gpg_key = msg['gpg_key'].sub('@', '_') + data = msg['data'] + + if data.nil? || data.empty? + send_msg = {:action => 'update', + :gpg_key => msg['gpg_key'], + :msg => 'update_fail', + :error => 'no_data'} + + return send_msg.to_json + end + + if msg['suffix'].nil? || msg['suffix'].empty? + file_gpg = "#{@data_dir}/#{gpg_key}.yml" + else + file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml" + end + + if File.exist?(file_gpg) + gpg_data = YAML::load_file(file_gpg) + salt = gpg_data['gpg']['salt'] + hash = gpg_data['gpg']['hash'] + + else + salt = MPW.generatePassword(4) + hash = Digest::SHA256.hexdigest(salt + msg['password']) + end + + if self.isAuthorized?(msg['password'], salt, hash) + begin + config = {'gpg' => {'salt' => salt, + 'hash' => hash, + 'data' => data}} + + File.open(file_gpg, 'w') do |file| + file << config.to_yaml + end + + send_msg = {:action => 'update', + :gpg_key => msg['gpg_key'], + :msg => 'update_done'} + rescue Exception => e + send_msg = {:action => 'update', + :gpg_key => msg['gpg_key'], + :msg => 'update_fail', + :error => e} + end + else + send_msg = {:action => 'update', + :gpg_key => msg['gpg_key'], + :msg => 'update_fail', + :error => 'not_autorized'} + end + + return send_msg.to_json + rescue Exception => e + puts e + end + end + + # Remove a gpg file + # @args: msg -> message puts by the client + # @rtrn: json message + def deleteFile(msg) + client.puts 'delete a file' + end + + # Check is the hash equal the password with the salt + # @args: password -> the user password + # salt -> the salt + # hash -> the hash of the password with the salt + # @rtrn: true is is good, else false + def isAuthorized?(password, salt, hash) + puts hash + puts YAML::dump(hash) + puts YAML::dump(Digest::SHA256.hexdigest(salt + password)) + puts Digest::SHA256.hexdigest(salt + password) + if hash == Digest::SHA256.hexdigest(salt + password) + return true + else + return false + end + end + + # Get message to client + # @args: client -> client connection + # @rtrn: array of the json string, or false if isn't json message + def getClientMessage(client) + begin + msg = client.gets + return JSON.parse(msg) + rescue + client.puts "Communication it's bad" + self.closeConnection(client) + return false + end + end + + # Close the client connection + # @args: client -> client connection + def closeConnection(client) + client.puts "Closing the connection. Bye!" + client.close + end + + # Check the config file + # @args: file_config -> the configuration file + # @rtrn: true if the config file is correct + def checkconfig(file_config) + begin + config = YAML::load_file(file_config) + @host = config['config']['host'] + @port = config['config']['port'] + @data_dir = config['config']['data_dir'] + @timeout = config['config']['timeout'].to_i + + if @host.empty? || @port.empty? + @error_msg = "Checkconfig failed!" + return false + end + + rescue Exception => e + @error_msg = "Checkconfig failed!\n#{e}" + return false + end + + return true + end + + # Create a new config file + # @args: file_config -> the configuration file + # @rtrn: true if le config file is create + def setup(file_config) + + puts I18n.t('server.form.setup.title') + puts '--------------------' + host = ask(I18n.t('server.form.setup.host')).to_s + port = ask(I18n.t('server.form.setup.port')).to_s + data_dir = ask(I18n.t('server.form.setup.data_dir')).to_s + timeout = ask(I18n.t('server.form.setup.timeout')).to_s + + config = {'config' => {'host' => host, + 'port' => port, + 'data_dir' => data_dir, + 'timeout' => timeout}} + + begin + File.open(file_config, 'w') do |file| + file << config.to_yaml + end + rescue Exception => e + @error_msg = "Can't write the config file!\n#{e}" + return false + end + + return true + end + +end diff --git a/mpw-server b/mpw-server new file mode 100755 index 0000000..f764037 --- /dev/null +++ b/mpw-server @@ -0,0 +1,46 @@ +#!/usr/bin/ruby +# author: nishiki +# mail: nishiki@yaegashi.fr +# info: a simple script who manage your passwords + +require 'rubygems' +require 'optparse' +require 'pathname' + +APP_ROOT = File.dirname(Pathname.new(__FILE__).realpath) +require "#{APP_ROOT}/lib/Server.rb" + +options = {} +OptionParser.new do |opts| + opts.banner = "Usage: mpw-server -c CONFIG [options]" + + opts.on("-c", "--config CONFIG", "Specifie the configuration file") do |config| + options[:config] = config + end + + opts.on("-t", "--check-config", "Check your configuration") do |b| + options[:checkconfig] = b + end + + opts.on("-s", "--setup", "Force a server") do |b| + options[:setup] = b + end + + opts.on("-h", "--help", "Show this message") do |b| + puts opts + exit 0 + end +end.parse! + +server = Server.new + +if options[:checkconfig] + server.checkconfig(options[:config]) +elsif options[:setup] + server.setup(options[:config]) +else + server.checkconfig(options[:config]) + server.start() +end + +exit 0 From f684ebe79b215d032471e6fe148fd61802c54b4c Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 18:01:56 +0100 Subject: [PATCH 02/27] remove debug exception --- lib/Server.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Server.rb b/lib/Server.rb index 77e4415..7c83e88 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -93,7 +93,6 @@ class Server # @args: msg -> message puts by the client # @rtrn: json message def updateFile(msg) - begin gpg_key = msg['gpg_key'].sub('@', '_') data = msg['data'] @@ -149,9 +148,6 @@ class Server end return send_msg.to_json - rescue Exception => e - puts e - end end # Remove a gpg file From 3662bcb2510e53bba5f279ffd9f698042d368c2d Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 18:12:24 +0100 Subject: [PATCH 03/27] add delete a gpg file --- lib/Server.rb | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/Server.rb b/lib/Server.rb index 7c83e88..b90a5f5 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -154,7 +154,48 @@ class Server # @args: msg -> message puts by the client # @rtrn: json message def deleteFile(msg) - client.puts 'delete a file' + gpg_key = msg['gpg_key'].sub('@', '_') + + if msg['suffix'].nil? || msg['suffix'].empty? + file_gpg = "#{@data_dir}/#{gpg_key}.yml" + else + file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml" + end + + if !File.exist?(file_gpg) + send_msg = {:action => 'delete', + :gpg_key => msg['gpg_key'], + :msg => 'delete_fail', + :error => 'file_not_exist'} + + return send_msg.to_json + end + + gpg_data = YAML::load_file(file_gpg) + salt = gpg_data['gpg']['salt'] + hash = gpg_data['gpg']['hash'] + + if self.isAuthorized?(msg['password'], salt, hash) + begin + File.unlink(file_gpg) + + send_msg = {:action => 'delete', + :gpg_key => msg['gpg_key'], + :msg => 'delete_done'} + rescue Exception => e + send_msg = {:action => 'delete', + :gpg_key => msg['gpg_key'], + :msg => 'delete_fail', + :error => e} + end + else + send_msg = {:action => 'delete', + :gpg_key => msg['gpg_key'], + :msg => 'delete_fail', + :error => 'not_autorized'} + end + + return send_msg.to_json end # Check is the hash equal the password with the salt @@ -163,10 +204,6 @@ class Server # hash -> the hash of the password with the salt # @rtrn: true is is good, else false def isAuthorized?(password, salt, hash) - puts hash - puts YAML::dump(hash) - puts YAML::dump(Digest::SHA256.hexdigest(salt + password)) - puts Digest::SHA256.hexdigest(salt + password) if hash == Digest::SHA256.hexdigest(salt + password) return true else From 8530f61b76eb0ccec291e8e780c65ccbf4b6967f Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 22:36:51 +0100 Subject: [PATCH 04/27] translate in french and in english --- i18n/en.yml | 15 +++++++++++++++ i18n/fr.yml | 15 +++++++++++++++ lib/Server.rb | 3 +-- mpw-server | 24 +++++++++++++++++++----- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index 6eecd3c..27a2d11 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -111,6 +111,21 @@ en: display: connect: "Connection to:" nothing: "Nothing result!" + server: + option: + usage: "Usage" + config: "Specifie the configuration file" + checkconfig: "Check the configuration" + setup: "Setup a new configuration file" + help: "Show this message help" + form: + setup: + title: "Serveur configuration" + host: "IP listen: " + port: "Port listen: " + data_dir: "Data directory: " + timeout: "Timeout to second: " + not_valid: "ERROR: Impossible to write the configuration file!" formats: default: ! '%Y-%m-%d' long: ! '%B %d, %Y' diff --git a/i18n/fr.yml b/i18n/fr.yml index ba433fb..770dd21 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -111,6 +111,21 @@ fr: display: connect: "Connexion à:" nothing: "Aucun résultat!" + server: + option: + usage: "Utilisation" + config: "Spécifie le fichier de configuration" + checkconfig: "Vérifie le fichier de configuration" + setup: "Permet de générer un nouveau fichier de configuration" + help: "Affiche ce message d'aide" + form: + setup: + title: "Configuration du serveur" + host: "IP d'écoute: " + port: "Port d'écoute: " + data_dir: "Répertoire des données: " + timeout: "Timeout en seconde: " + not_valid: "ERREUR: Impossible d'écire le fichier de configuration!" formats: default: ! '%Y-%m-%d' long: ! '%B %d, %Y' diff --git a/lib/Server.rb b/lib/Server.rb index b90a5f5..77ee2c2 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -260,7 +260,6 @@ class Server # @args: file_config -> the configuration file # @rtrn: true if le config file is create def setup(file_config) - puts I18n.t('server.form.setup.title') puts '--------------------' host = ask(I18n.t('server.form.setup.host')).to_s @@ -278,7 +277,7 @@ class Server file << config.to_yaml end rescue Exception => e - @error_msg = "Can't write the config file!\n#{e}" + puts "#{I18n.t('server.formsetup.not_valid')}\n#{e}" return false end diff --git a/mpw-server b/mpw-server index f764037..3143b59 100755 --- a/mpw-server +++ b/mpw-server @@ -6,32 +6,46 @@ require 'rubygems' require 'optparse' require 'pathname' +require 'locale' +require 'i18n' APP_ROOT = File.dirname(Pathname.new(__FILE__).realpath) require "#{APP_ROOT}/lib/Server.rb" +lang = Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] + +I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) +I18n.load_path = Dir["#{APP_ROOT}/i18n/*.yml"] +I18n.default_locale = :en +I18n.locale = lang.to_sym + options = {} OptionParser.new do |opts| - opts.banner = "Usage: mpw-server -c CONFIG [options]" + opts.banner = "#{I18n.t('server.option.usage')}: mpw-server -c CONFIG [options]" - opts.on("-c", "--config CONFIG", "Specifie the configuration file") do |config| + opts.on("-c", "--config CONFIG", I18n.t('server.option.config')) do |config| options[:config] = config end - opts.on("-t", "--check-config", "Check your configuration") do |b| + opts.on("-t", "--checkconfig", I18n.t('server.option.checkconfig')) do |b| options[:checkconfig] = b end - opts.on("-s", "--setup", "Force a server") do |b| + opts.on("-s", "--setup", I18n.t('server.option.setup')) do |b| options[:setup] = b end - opts.on("-h", "--help", "Show this message") do |b| + opts.on("-h", "--help", I18n.t('server.option.help')) do |b| puts opts exit 0 end end.parse! +if options[:config].nil? || options[:config].empty? + puts "#{I18n.t('server.option.usage')}: mpw-server -c CONFIG [options]" + exit 2 +end + server = Server.new if options[:checkconfig] From c0751b3b25344585b34091d2d884c15ffd4bef85 Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 22:49:22 +0100 Subject: [PATCH 05/27] translate checkconfig --- i18n/en.yml | 4 ++++ i18n/fr.yml | 4 ++++ lib/Server.rb | 14 ++++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index 27a2d11..9a4781a 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -118,6 +118,10 @@ en: checkconfig: "Check the configuration" setup: "Setup a new configuration file" help: "Show this message help" + checkconfig: + fail: "Checkconfig failed:!" + empty: "ERROR: an importe option is missing!" + datadir: "ERROR: le data directory doesn't exist!" form: setup: title: "Serveur configuration" diff --git a/i18n/fr.yml b/i18n/fr.yml index 770dd21..74924b7 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -118,6 +118,10 @@ fr: checkconfig: "Vérifie le fichier de configuration" setup: "Permet de générer un nouveau fichier de configuration" help: "Affiche ce message d'aide" + checkconfig: + fail: "Le fichier de configuration est invalide!" + empty: "ERREUR: Une option importante est manquante!" + datadir: "ERREUR: Le répertoire des données n'existe pas!" form: setup: title: "Configuration du serveur" diff --git a/lib/Server.rb b/lib/Server.rb index 77ee2c2..699b355 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -15,7 +15,6 @@ class Server # Constructor def initialize() YAML::ENGINE.yamler='syck' - @error_msg = nil end # Start the server @@ -243,13 +242,20 @@ class Server @data_dir = config['config']['data_dir'] @timeout = config['config']['timeout'].to_i - if @host.empty? || @port.empty? - @error_msg = "Checkconfig failed!" + if @host.empty? || @port.empty? || @data_dir.empty? + puts I18n.t('server.checkconfig.fail') + puts I18n.t('server.checkconfig.empty') + return false + end + + if !Dir.exist?(@data_dir) + puts I18n.t('server.checkconfig.fail') + puts I18n.t('server.checkconfig.datadir') return false end rescue Exception => e - @error_msg = "Checkconfig failed!\n#{e}" + puts "#{I18n.t('server.checkconfig.fail')}\n#{e}" return false end From 55db474039e1c43dbbb87ba8dca6e1ea63915186 Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 22:52:55 +0100 Subject: [PATCH 06/27] remove require base64 --- lib/Server.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Server.rb b/lib/Server.rb index 699b355..737d9da 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -4,7 +4,6 @@ require 'socket' require 'json' require 'highline/import' require 'digest' -require 'base64' require "#{APP_ROOT}/lib/MPW.rb" From 6b9474e5384920a5e9621455779d822efd53716d Mon Sep 17 00:00:00 2001 From: nishiki Date: Sat, 11 Jan 2014 15:49:22 +0100 Subject: [PATCH 07/27] fix problem in translate file --- i18n/en.yml | 10 +++++----- i18n/fr.yml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index 9a4781a..c2203c4 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -125,11 +125,11 @@ en: form: setup: title: "Serveur configuration" - host: "IP listen: " - port: "Port listen: " - data_dir: "Data directory: " - timeout: "Timeout to second: " - not_valid: "ERROR: Impossible to write the configuration file!" + host: "IP listen: " + port: "Port listen: " + data_dir: "Data directory: " + timeout: "Timeout to second: " + not_valid: "ERROR: Impossible to write the configuration file!" formats: default: ! '%Y-%m-%d' long: ! '%B %d, %Y' diff --git a/i18n/fr.yml b/i18n/fr.yml index 74924b7..a1323be 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -125,11 +125,11 @@ fr: form: setup: title: "Configuration du serveur" - host: "IP d'écoute: " - port: "Port d'écoute: " - data_dir: "Répertoire des données: " - timeout: "Timeout en seconde: " - not_valid: "ERREUR: Impossible d'écire le fichier de configuration!" + host: "IP d'écoute: " + port: "Port d'écoute: " + data_dir: "Répertoire des données: " + timeout: "Timeout en seconde: " + not_valid: "ERREUR: Impossible d'écire le fichier de configuration!" formats: default: ! '%Y-%m-%d' long: ! '%B %d, %Y' From e0a120d8f12855c01349398e84c2935ab2392435 Mon Sep 17 00:00:00 2001 From: nishiki Date: Sun, 12 Jan 2014 00:37:46 +0100 Subject: [PATCH 08/27] restructiring the code --- lib/Cli.rb | 58 +++++++++++++------------ lib/MPW.rb | 87 +++---------------------------------- lib/MPWConfig.rb | 109 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 108 deletions(-) create mode 100644 lib/MPWConfig.rb diff --git a/lib/Cli.rb b/lib/Cli.rb index cc67cd1..4947c00 100644 --- a/lib/Cli.rb +++ b/lib/Cli.rb @@ -10,6 +10,7 @@ require 'readline' require 'i18n' require "#{APP_ROOT}/lib/MPW.rb" +require "#{APP_ROOT}/lib/MPWConfig.rb" class Cli @@ -17,14 +18,15 @@ class Cli # @args: lang -> the operating system language # config_file -> a specify config file def initialize(lang, config_file=nil) - @m = MPW.new(config_file) + @config = MPWConfig.new(config_file) - if not @m.checkconfig() + if not @config.checkconfig() self.setup(lang) end + @mpw = MPW.new(@config.file_gpg, @config.key) if not self.decrypt() - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" exit 2 end end @@ -44,28 +46,28 @@ class Cli end I18n.locale = language.to_sym - if @m.setup(key, language, file_gpg, timeout_pwd) + if @config.setup(key, language, file_gpg, timeout_pwd) puts I18n.t('cli.form.setup.valid') else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@config.error_msg}" end - if not @m.checkconfig() - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + if not @config.checkconfig() + puts "#{I18n.t('cli.display.error')}: #{@config.error_msg}" end end # Request the GPG password and decrypt the file def decrypt() @passwd = ask(I18n.t('cli.display.gpg_password')) {|q| q.echo = false} - return @m.decrypt(@passwd) + return @mpw.decrypt(@passwd) end # Display the query's result # @args: search -> the string to search # protocol -> search from a particular protocol def display(search, protocol=nil, group=nil, format=nil) - result = @m.search(search, group, protocol) + result = @mpw.search(search, group, protocol) if not result.empty? result.each do |r| @@ -125,21 +127,21 @@ class Cli port = ask(I18n.t('cli.form.add.port')).to_s comment = ask(I18n.t('cli.form.add.comment')).to_s - if @m.add(name, group, server, protocol, login, passwd, port, comment) - if @m.encrypt() + if @mpw.add(name, group, server, protocol, login, passwd, port, comment) + if @mpw.encrypt() puts I18n.t('cli.form.add.valid') else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end end # Update an item # @args: id -> the item's id def update(id) - row = @m.searchById(id) + row = @mpw.searchById(id) if not row.empty? puts I18n.t('cli.form.update.title') @@ -153,14 +155,14 @@ class Cli port = ask(I18n.t('cli.form.update.port' , :port => row[MPW::PORT])).to_s comment = ask(I18n.t('cli.form.update.comment' , :comment => row[MPW::COMMENT])).to_s - if @m.update(id, name, group, server, protocol, login, passwd, port, comment) - if @m.encrypt() + if @mpw.update(id, name, group, server, protocol, login, passwd, port, comment) + if @mpw.encrypt() puts I18n.t('cli.form.update.valid') else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end else puts I18n.t('cli.display.nothing') @@ -172,7 +174,7 @@ class Cli # force -> no resquest a validation def remove(id, force=false) if not force - result = @m.searchById(id) + result = @mpw.searchById(id) if result.length > 0 self.displayFormat(result) @@ -187,11 +189,11 @@ class Cli end if force - if @m.remove(id) - if @m.encrypt() + if @mpw.remove(id) + if @mpw.encrypt() puts I18n.t('cli.form.delete.valid', :id => id) else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end else puts I18n.t('cli.form.delete.not_valid') @@ -202,10 +204,10 @@ class Cli # Export the items in a CSV file # @args: file -> the destination file def export(file) - if @m.export(file) + if @mpw.export(file) puts "The export in #{file} is succesfull!" else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end end @@ -214,7 +216,7 @@ class Cli # @args: file -> the import file # force -> no resquest a validation def import(file, force=false) - result = @m.importPreview(file) + result = @mpw.importPreview(file) if not force if result.is_a?(Array) && !result.empty? @@ -232,10 +234,10 @@ class Cli end if force - if @m.import(file) && @m.encrypt() + if @mpw.import(file) && @mpw.encrypt() puts I18n.t('cli.form.import.valid') else - puts "#{I18n.t('cli.display.error')}: #{@m.error_msg}" + puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" end end end @@ -247,7 +249,7 @@ class Cli while buf = Readline.readline(' ', true) - if @m.timeout_pwd < Time.now.to_i - last_access + if @config.timeout_pwd < Time.now.to_i - last_access passwd_confirm = ask(I18n.t('cli.interactive.ask_password')) {|q| q.echo = false} if @passwd.eql?(passwd_confirm) diff --git a/lib/MPW.rb b/lib/MPW.rb index e38ec0a..937ecdf 100644 --- a/lib/MPW.rb +++ b/lib/MPW.rb @@ -6,7 +6,6 @@ require 'rubygems' require 'gpgme' require 'csv' -require 'yaml' require 'i18n' class MPW @@ -22,79 +21,12 @@ class MPW COMMENT = 8 attr_accessor :error_msg - attr_accessor :timeout_pwd - + # Constructor - # @args: file_config -> the specify config file - def initialize(file_config=nil) - @error_msg = nil - @file_config = "#{Dir.home()}/.mpw.cfg" - - if !file_config.nil? && !file_config.empty? - @file_config = file_config - end - end - - # Create a new config file - # @args: key -> the gpg key to encrypt - # lang -> the software language - # file_gpg -> the file who is encrypted - # file_pwd -> the file who stock the password - # timeout_pwd -> time to save the password - # @rtrn: true if le config file is create - def setup(key, lang, file_gpg, timeout_pwd) - - 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 file_gpg.empty? - file_gpg = "#{Dir.home()}/.mpw.gpg" - end - - timeout_pwd.empty? ? (timeout_pwd = 60) : (timeout_pwd = timeout_pwd.to_i) - - config = {'config' => {'key' => key, - 'lang' => lang, - 'file_gpg' => file_gpg, - 'timeout_pwd' => timeout_pwd}} - - 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 - end - - return true - 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 - - 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}" - return false - end - - return true + def initialize(file_gpg, key=nil) + @error_msg = nil + @file_gpg = file_gpg + @key = key end # Decrypt a gpg file @@ -117,10 +49,6 @@ class MPW return true rescue Exception => e - if !@file_pwd.nil? && File.exist?(@file_pwd) - File.delete(@file_pwd) - end - @error_msg = "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" return false end @@ -327,7 +255,7 @@ class MPW end end - # Return + # 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 importPreview(file) @@ -372,7 +300,6 @@ class MPW result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join return result - #return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]-%w(0 1 I O l i o)).sample(length).join end - + end diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb new file mode 100644 index 0000000..25dac98 --- /dev/null +++ b/lib/MPWConfig.rb @@ -0,0 +1,109 @@ +#!/usr/bin/ruby +# author: nishiki +# mail: nishiki@yaegashi.fr +# info: a simple script who manage your passwords + +require 'rubygems' +require 'yaml' +require 'i18n' + +class MPWConfig + + attr_accessor :error_msg + + attr_accessor :key + attr_accessor :lang + attr_accessor :file_gpg + attr_accessor :timeout_pwd + attr_accessor :sync_host + attr_accessor :sync_port + attr_accessor :sync_pwd + attr_accessor :sync_sufix + + # Constructor + # @args: file_config -> the specify config file + def initialize(file_config=nil) + @error_msg = nil + @file_config = "#{Dir.home()}/.mpw.cfg" + + if !file_config.nil? && !file_config.empty? + @file_config = file_config + end + end + + # Create a new config file + # @args: key -> the gpg key to encrypt + # lang -> the software language + # file_gpg -> the file who is encrypted + # timeout_pwd -> time to save the password + # @rtrn: true if le config file is create + def setup(key, lang, file_gpg, timeout_pwd) + + 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 file_gpg.empty? + file_gpg = "#{Dir.home()}/.mpw.gpg" + end + + timeout_pwd.empty? ? (timeout_pwd = 60) : (timeout_pwd = timeout_pwd.to_i) + + config = {'config' => {'key' => key, + 'lang' => lang, + 'file_gpg' => file_gpg, + 'timeout_pwd' => timeout_pwd, + 'sync_host' => host, + 'sync_port' => port, + 'sync_pwd' => password, + 'sync_suffix' => suffix}} + + 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 + end + + return true + 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_sufix = config['config']['sync_suffix'] + + 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}" + return false + end + + begin + @sync = TCPSocket.new(@sync_host, @sync_port) + rescue + @sync = false + end + + return true + end + +end From 9067a67d506035796d73b6df5079ee8e601048e3 Mon Sep 17 00:00:00 2001 From: nishiki Date: Sun, 12 Jan 2014 00:40:58 +0100 Subject: [PATCH 09/27] remove tcp test --- lib/MPWConfig.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb index 25dac98..a59f3b5 100644 --- a/lib/MPWConfig.rb +++ b/lib/MPWConfig.rb @@ -97,12 +97,6 @@ class MPWConfig return false end - begin - @sync = TCPSocket.new(@sync_host, @sync_port) - rescue - @sync = false - end - return true end From 477178ecdd13f19775552a464fa5458a9ce21254 Mon Sep 17 00:00:00 2001 From: nishiki Date: Sun, 12 Jan 2014 11:07:54 +0100 Subject: [PATCH 10/27] add last_update --- lib/Server.rb | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/Server.rb b/lib/Server.rb index 737d9da..307d0b6 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -61,26 +61,28 @@ class Server end if File.exist?(file_gpg) - gpg_data = YAML::load_file(file_gpg) - salt = gpg_data['gpg']['salt'] - hash = gpg_data['gpg']['hash'] - data = gpg_data['gpg']['data'] + gpg_data = YAML::load_file(file_gpg) + salt = gpg_data['gpg']['salt'] + hash = gpg_data['gpg']['hash'] + data = gpg_data['gpg']['data'] + last_update = gpg_data['gpg']['last_update'] if self.isAuthorized?(msg['password'], salt, hash) send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], - :msg => 'get_done', + :last_update => last_update, + :msg => 'done', :data => data} else send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], - :msg => 'get_fail', + :msg => 'fail', :error => 'not_authorized'} end else send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], - :msg => 'get_fail', + :msg => 'fail', :error => 'file_not_exist'} end @@ -97,7 +99,7 @@ class Server if data.nil? || data.empty? send_msg = {:action => 'update', :gpg_key => msg['gpg_key'], - :msg => 'update_fail', + :msg => 'fail', :error => 'no_data'} return send_msg.to_json @@ -121,27 +123,30 @@ class Server if self.isAuthorized?(msg['password'], salt, hash) begin - config = {'gpg' => {'salt' => salt, - 'hash' => hash, - 'data' => data}} + last_update = Time.now.to_i + config = {'gpg' => {'salt' => salt, + 'hash' => hash, + 'last_update' => last_update + 'data' => data}} File.open(file_gpg, 'w') do |file| file << config.to_yaml end - send_msg = {:action => 'update', - :gpg_key => msg['gpg_key'], - :msg => 'update_done'} + send_msg = {:action => 'update', + :gpg_key => msg['gpg_key'], + :last_update => last_update + :msg => 'done'} rescue Exception => e send_msg = {:action => 'update', :gpg_key => msg['gpg_key'], - :msg => 'update_fail', - :error => e} + :msg => 'fail', + :error => 'server_error'} end else send_msg = {:action => 'update', :gpg_key => msg['gpg_key'], - :msg => 'update_fail', + :msg => 'fail', :error => 'not_autorized'} end From b9988102d6dda915ce1e3cb8a4bee4a9dc2569f3 Mon Sep 17 00:00:00 2001 From: nishiki Date: Sun, 12 Jan 2014 11:36:56 +0100 Subject: [PATCH 11/27] add last_update in MPWConfig --- lib/MPWConfig.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb index a59f3b5..a402ee3 100644 --- a/lib/MPWConfig.rb +++ b/lib/MPWConfig.rb @@ -19,11 +19,12 @@ class MPWConfig attr_accessor :sync_port attr_accessor :sync_pwd attr_accessor :sync_sufix + attr_accessor :sync_last_update # Constructor # @args: file_config -> the specify config file def initialize(file_config=nil) - @error_msg = nil + @error_msg = nil @file_config = "#{Dir.home()}/.mpw.cfg" if !file_config.nil? && !file_config.empty? @@ -57,7 +58,8 @@ class MPWConfig 'sync_host' => host, 'sync_port' => port, 'sync_pwd' => password, - 'sync_suffix' => suffix}} + 'sync_suffix' => suffix, + 'last_update' => 0 }} begin File.open(@file_config, 'w') do |file| @@ -76,14 +78,15 @@ class MPWConfig 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_sufix = config['config']['sync_suffix'] + @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_sufix = config['config']['sync_suffix'] + @sync_last_update = config['config']['sync_last_update'].to_i if @key.empty? || @file_gpg.empty? @error_msg = I18n.t('error.config.check') From d458a09a75c5fd6fc3f7fd0c25a9703e58af4ebb Mon Sep 17 00:00:00 2001 From: nishiki Date: Sun, 12 Jan 2014 14:09:32 +0100 Subject: [PATCH 12/27] fix bug --- lib/Server.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Server.rb b/lib/Server.rb index 307d0b6..361835a 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -126,7 +126,7 @@ class Server last_update = Time.now.to_i config = {'gpg' => {'salt' => salt, 'hash' => hash, - 'last_update' => last_update + 'last_update' => last_update, 'data' => data}} File.open(file_gpg, 'w') do |file| @@ -135,7 +135,7 @@ class Server send_msg = {:action => 'update', :gpg_key => msg['gpg_key'], - :last_update => last_update + :last_update => last_update, :msg => 'done'} rescue Exception => e send_msg = {:action => 'update', From bc276f23c11bc953f2975e7f2a70659459d7f265 Mon Sep 17 00:00:00 2001 From: nishiki Date: Mon, 13 Jan 2014 20:07:15 +0100 Subject: [PATCH 13/27] add uniq id and date time --- lib/MPW.rb | 94 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/lib/MPW.rb b/lib/MPW.rb index 937ecdf..1bd4392 100644 --- a/lib/MPW.rb +++ b/lib/MPW.rb @@ -19,6 +19,7 @@ class MPW PASSWORD = 6 PORT = 7 COMMENT = 8 + DATE = 9 attr_accessor :error_msg @@ -40,10 +41,8 @@ class MPW crypto = GPGME::Crypto.new(:armor => true) data_decrypt = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read - id = 0 data_decrypt.lines do |line| - @data[id] = line.parse_csv.unshift(id) - id += 1; + @data.push(line.parse_csv) end end @@ -63,7 +62,7 @@ class MPW data_to_encrypt = '' @data.each do |row| - data_to_encrypt << row.drop(1).to_csv + data_to_encrypt << row.to_csv end crypto.encrypt(data_to_encrypt, :recipients => @key, :output => file_gpg) @@ -107,11 +106,13 @@ class MPW # @args: id -> the id item # @rtrn: a row with the resultat of the search def searchById(id) - if not @data[id.to_i].nil? - return @data[id.to_i] - else - return Array.new + @data.each do |row| + if @data[ID] == id + return row + end end + + return Array.new() end # Add a new item @@ -136,16 +137,10 @@ class MPW port = nil end - if not @data.last.nil? - id = @data.last - id = id[ID].to_i + 1 - else - id = 0 - end - - row[ID] = id + row[ID] = MPW.generatePassword(16) row[PORT] = port row[NAME] = name.force_encoding('ASCII-8BIT') + row[DATE] = Time.now.to_i group.nil? || group.empty? ? (row[GROUP] = nil) : (row[GROUP] = group.force_encoding('ASCII-8BIT')) server.nil? || server.empty? ? (row[SERVER] = nil) : (row[SERVER] = server.force_encoding('ASCII-8BIT')) protocol.nil? || protocol.empty? ? (row[PROTOCOL] = nil) : (row[PROTOCOL] = protocol.force_encoding('ASCII-8BIT')) @@ -153,7 +148,7 @@ class MPW passwd.nil? || passwd.empty? ? (row[PASSWORD] = nil) : (row[PASSWORD] = passwd.force_encoding('ASCII-8BIT')) comment.nil? || comment.empty? ? (row[COMMENT] = nil) : (row[COMMENT] = comment.force_encoding('ASCII-8BIT')) - @data[id] = row + @data.push(row) return true end @@ -170,45 +165,54 @@ class MPW # comment -> a comment # @rtrn: true if the item has been updated def update(id, name=nil, group=nil, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil) - id = id.to_i + i = 0 - if not @data[id].nil? + @data.each do |row| + if not row[ID] == id - if port.to_i <= 0 - port = nil + if port.to_i <= 0 + port = nil + end + + row_update = Array.new() + row[DATE] = Time.now.to_i + + name.nil? || name.empty? ? (row_update[NAME] = row[NAME]) : (row_update[NAME] = name) + group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group) + server.nil? || server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server) + protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol) + login.nil? || login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login) + passwd.nil? || passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd) + port.nil? || port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port) + comment.nil? || comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment) + + @data[i] = row_update + + return true end - row = @data[id] - row_update = Array.new() - - name.nil? || name.empty? ? (row_update[NAME] = row[NAME]) : (row_update[NAME] = name) - group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group) - server.nil? || server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server) - protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol) - login.nil? || login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login) - passwd.nil? || passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd) - port.nil? || port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port) - comment.nil? || comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment) - - @data[id] = row_update - - return true - else - @error_msg = I18n.t('error.update.id_no_exist', :id => id) - return false + i += 1 end + + @error_msg = I18n.t('error.update.id_no_exist', :id => id) + return false end # Remove an item # @args: id -> the item's identifiant # @rtrn: true if the item has been deleted def remove(id) - if not @data.delete_at(id.to_i).nil? - return true - else - @error_msg = I18n.t('error.delete.id_no_exist', :id => id) - return false + i = 0 + @data.each do |row| + if row[ID] == id + @data.delete(i) + return true + end + i += 1 end + + @error_msg = I18n.t('error.delete.id_no_exist', :id => id) + return false end # Export to csv @@ -218,7 +222,7 @@ class MPW begin File.open(file, 'w+') do |file| @data.each do |row| - row.delete_at(ID) + row.delete_at(ID).delete_at(DATE) file << row.to_csv end end From 8b86040af0f16efde46e55bc1d7fe4a980eb2b30 Mon Sep 17 00:00:00 2001 From: nishiki Date: Tue, 14 Jan 2014 23:00:52 +0100 Subject: [PATCH 14/27] first sync work :) --- lib/Cli.rb | 19 +++++++++ lib/MPW.rb | 58 +++++++++++++++++++++++--- lib/MPWConfig.rb | 46 ++++++++++++++++----- lib/Server.rb | 68 ++++++++++++++++-------------- lib/Sync.rb | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 48 deletions(-) create mode 100644 lib/Sync.rb diff --git a/lib/Cli.rb b/lib/Cli.rb index 4947c00..aab3242 100644 --- a/lib/Cli.rb +++ b/lib/Cli.rb @@ -8,9 +8,11 @@ require 'highline/import' require 'pathname' require 'readline' require 'i18n' +require 'yaml' require "#{APP_ROOT}/lib/MPW.rb" require "#{APP_ROOT}/lib/MPWConfig.rb" +require "#{APP_ROOT}/lib/Sync.rb" class Cli @@ -29,6 +31,23 @@ class Cli puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" exit 2 end + + @sync = Sync.new() + if @config.sync_host.nil? || @config.sync_port.nil? + @sync.disable() + elsif !@sync.connect(@config.sync_host, @config.sync_port, @config.key, @config.sync_pwd, @config.sync_suffix) + puts "#{I18n.t('cli.sync.not_connect')}:\n#{@sync.error_msg}" + else + begin + @mpw.sync(@sync.get(@passwd), @config.last_update) + @sync.update(File.open(@config.file_gpg).read) + @config.setLastUpdate() + rescue Exception => e + puts "#{I18n.t('cli.sync.error')}:\n#{e}" + else + @sync.close() + end + end end # Create a new config file diff --git a/lib/MPW.rb b/lib/MPW.rb index 1bd4392..1d15076 100644 --- a/lib/MPW.rb +++ b/lib/MPW.rb @@ -79,7 +79,7 @@ class MPW # @args: search -> the string to search # protocol -> the connection protocol (ssh, web, other) # @rtrn: a list with the resultat of the search - def search(search, group=nil, protocol=nil) + def search(search='', group=nil, protocol=nil) result = Array.new() if !search.nil? @@ -107,7 +107,7 @@ class MPW # @rtrn: a row with the resultat of the search def searchById(id) @data.each do |row| - if @data[ID] == id + if row[ID] == id return row end end @@ -168,14 +168,15 @@ class MPW i = 0 @data.each do |row| - if not row[ID] == id + if row[ID] == id if port.to_i <= 0 port = nil end - row_update = Array.new() - row[DATE] = Time.now.to_i + row_update = Array.new() + row_update[ID] = row[ID] + row_update[DATE] = Time.now.to_i name.nil? || name.empty? ? (row_update[NAME] = row[NAME]) : (row_update[NAME] = name) group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group) @@ -205,7 +206,7 @@ class MPW i = 0 @data.each do |row| if row[ID] == id - @data.delete(i) + @data.delete_at(i) return true end i += 1 @@ -286,6 +287,51 @@ class MPW end end + # Sync remote data and local data + # @args: data_remote -> array with the data remote + # last_update -> last update + # @rtrn: false if data_remote is nil + def sync(data_remote, last_update) + if !data_remote.instance_of?(Array) + return false + end + + @data.each do |l| + j = 0 + update = false + + # Update item + data_remote.each do |r| + if l[ID] == r[ID] + if l[DATE].to_i < r[DATE].to_i + self.update(l[ID], r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT]) + end + update = true + data_remote.delete_at(j) + break + end + j += 1 + end + + # Delete an old item + if !update && l[DATE].to_i < last_update + self.remove(l[ID]) + end + end + + # Add item + data_remote.each do |r| + if r[DATE].to_i > last_update + puts 'add' + @data.push(r) + end + end + + self.encrypt() + + return true + end + # Generate a random password # @args: length -> the length password # @rtrn: a random string diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb index a402ee3..790f34e 100644 --- a/lib/MPWConfig.rb +++ b/lib/MPWConfig.rb @@ -15,11 +15,12 @@ class MPWConfig attr_accessor :lang attr_accessor :file_gpg attr_accessor :timeout_pwd + attr_accessor :last_update attr_accessor :sync_host attr_accessor :sync_port attr_accessor :sync_pwd - attr_accessor :sync_sufix - attr_accessor :sync_last_update + attr_accessor :sync_suffix + attr_accessor :last_update # Constructor # @args: file_config -> the specify config file @@ -78,15 +79,15 @@ class MPWConfig 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_sufix = config['config']['sync_suffix'] - @sync_last_update = config['config']['sync_last_update'].to_i + @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_sufix = 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') @@ -102,5 +103,28 @@ class MPWConfig return true end + + def setLastUpdate() + config = {'config' => {'key' => @key, + 'lang' => @lang, + 'file_gpg' => @file_gpg, + 'timeout_pwd' => @timeout_pwd, + 'sync_host' => @sync_host, + 'sync_port' => @sync_port, + 'sync_pwd' => @sync_pwd, + 'sync_suffix' => @sync_uffix, + '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 + end + + return true + end end diff --git a/lib/Server.rb b/lib/Server.rb index 361835a..59d377c 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -21,29 +21,33 @@ class Server server = TCPServer.open(@host, @port) loop do Thread.start(server.accept) do |client| - msg = self.getClientMessage(client) + while true do + msg = self.getClientMessage(client) - if !msg - next - end - - if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty? - self.closeConnection(client) - next - end + if !msg + next + end + + if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty? + self.closeConnection(client) + next + end - case msg['action'] - when 'get' - client.puts self.getFile(msg) - when 'update' - client.puts self.updateFile(msg) - when 'delete' - client.puts self.deleteFile(msg) - else - client.puts 'Unknown command' + case msg['action'] + when 'get' + client.puts self.getFile(msg) + when 'update' + client.puts self.updateFile(msg) + puts 'update' + when 'delete' + client.puts self.deleteFile(msg) + when 'close' + self.closeConnection(client) + else + client.puts 'Unknown command' + self.closeConnection(client) + end end - - self.closeConnection(client) end end end @@ -68,11 +72,11 @@ class Server last_update = gpg_data['gpg']['last_update'] if self.isAuthorized?(msg['password'], salt, hash) - send_msg = {:action => 'get', - :gpg_key => msg['gpg_key'], + send_msg = {:action => 'get', + :gpg_key => msg['gpg_key'], :last_update => last_update, - :msg => 'done', - :data => data} + :msg => 'done', + :data => data} else send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], @@ -80,10 +84,12 @@ class Server :error => 'not_authorized'} end else - send_msg = {:action => 'get', - :gpg_key => msg['gpg_key'], - :msg => 'fail', - :error => 'file_not_exist'} + send_msg = {:action => 'get', + :gpg_key => msg['gpg_key'], + :last_update => 0, + :data => '', + :msg => 'fail', + :error => 'file_not_exist'} end return send_msg.to_json @@ -129,7 +135,7 @@ class Server 'last_update' => last_update, 'data' => data}} - File.open(file_gpg, 'w') do |file| + File.open(file_gpg, 'w+') do |file| file << config.to_yaml end @@ -242,11 +248,11 @@ class Server begin config = YAML::load_file(file_config) @host = config['config']['host'] - @port = config['config']['port'] + @port = config['config']['port'].to_i @data_dir = config['config']['data_dir'] @timeout = config['config']['timeout'].to_i - if @host.empty? || @port.empty? || @data_dir.empty? + if @host.empty? || @port <= 0 || @data_dir.empty? puts I18n.t('server.checkconfig.fail') puts I18n.t('server.checkconfig.empty') return false diff --git a/lib/Sync.rb b/lib/Sync.rb new file mode 100644 index 0000000..99f7d81 --- /dev/null +++ b/lib/Sync.rb @@ -0,0 +1,105 @@ +#!/usr/bin/ruby +# author: nishiki +# mail: nishiki@yaegashi.fr +# info: a simple script who manage your passwords + +require 'rubygems' +require 'i18n' +require 'socket' +require 'json' + +require "#{APP_ROOT}/lib/MPW.rb" + +class Sync + + attr_accessor :error_msg + + def initialize() + @error_msg = nil + end + + def disable() + @sync = false + end + + def connect(host, port, gpg_key, password, suffix=nil) + @gpg_key = gpg_key + @password = password + @suffix = suffix + + begin + @socket= TCPSocket.new(host, port) + @sync = true + rescue Exception => e + @error_msg = "ERROR: Connection impossible\n#{e}" + @sync = false + end + + return @sync + end + + def get(gpg_password) + send_msg = {:action => 'get', + :gpg_key => @gpg_key, + :password => @password, + :suffix => @suffix} + + @socket.puts send_msg.to_json + msg = JSON.parse(@socket.gets) + + case msg['error'] + when nil, 'file_not_exist' + tmp_file = "/tmp/mpw-#{MPW.generatePassword()}.gpg" + File.open(tmp_file, 'w') do |file| + file << msg['data'] + end + + @mpw = MPW.new(tmp_file) + if !@mpw.decrypt(gpg_password) + return nil + end + + File.unlink(tmp_file) + + return @mpw.search() + when 'not_authorized' + @error_msg = 'not authorized' + else + @error_msg = 'error unknow' + end + + return nil + end + + def update(data) + send_msg = {:action => 'update', + :gpg_key => @gpg_key, + :password => @password, + :suffix => @suffix, + :data => data} + + @socket.puts send_msg.to_json + msg = JSON.parse(@socket.gets) + + case msg['error'] + when nil + return true + when 'not_authorized' + @error_msg = 'not authorized' + when 'no_data' + @error_msg = 'no data' + else + @error_msg = 'error unknow' + end + + return false + end + + def delete() + end + + def close() + send_msg = {:action => 'close'} + @socket.puts send_msg.to_json + end +end From e8c315403e0c76527ea8c987fd155b50282d7a33 Mon Sep 17 00:00:00 2001 From: nishiki Date: Tue, 14 Jan 2014 23:20:17 +0100 Subject: [PATCH 15/27] remove dev debug --- lib/Server.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Server.rb b/lib/Server.rb index 59d377c..d3b561b 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -38,7 +38,6 @@ class Server client.puts self.getFile(msg) when 'update' client.puts self.updateFile(msg) - puts 'update' when 'delete' client.puts self.deleteFile(msg) when 'close' From 213743bad22abc8cdc8752a91f8a756f199e0d15 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:01:23 +0100 Subject: [PATCH 16/27] fusion MPW:add and MPW:update --- lib/Cli.rb | 22 +++++----- lib/MPW.rb | 115 ++++++++++++++++++++--------------------------------- 2 files changed, 54 insertions(+), 83 deletions(-) diff --git a/lib/Cli.rb b/lib/Cli.rb index aab3242..ed28ca2 100644 --- a/lib/Cli.rb +++ b/lib/Cli.rb @@ -23,11 +23,11 @@ class Cli @config = MPWConfig.new(config_file) if not @config.checkconfig() - self.setup(lang) + setup(lang) end @mpw = MPW.new(@config.file_gpg, @config.key) - if not self.decrypt() + if not decrypt() puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}" exit 2 end @@ -91,9 +91,9 @@ class Cli if not result.empty? result.each do |r| if format.nil? || !format - self.displayFormat(r) + displayFormat(r) else - self.displayFormatAlt(r) + displayFormatAlt(r) end end else @@ -146,7 +146,7 @@ class Cli port = ask(I18n.t('cli.form.add.port')).to_s comment = ask(I18n.t('cli.form.add.comment')).to_s - if @mpw.add(name, group, server, protocol, login, passwd, port, comment) + if @mpw.update(name, group, server, protocol, login, passwd, port, comment) if @mpw.encrypt() puts I18n.t('cli.form.add.valid') else @@ -174,7 +174,7 @@ class Cli port = ask(I18n.t('cli.form.update.port' , :port => row[MPW::PORT])).to_s comment = ask(I18n.t('cli.form.update.comment' , :comment => row[MPW::COMMENT])).to_s - if @mpw.update(id, name, group, server, protocol, login, passwd, port, comment) + if @mpw.update(name, group, server, protocol, login, passwd, port, comment, id) if @mpw.encrypt() puts I18n.t('cli.form.update.valid') else @@ -196,7 +196,7 @@ class Cli result = @mpw.searchById(id) if result.length > 0 - self.displayFormat(result) + displayFormat(result) confirm = ask("#{I18n.t('cli.form.delete.ask', :id => id)} (y/N) ").to_s if confirm =~ /^(y|yes|YES|Yes|Y)$/ @@ -240,7 +240,7 @@ class Cli if not force if result.is_a?(Array) && !result.empty? result.each do |r| - self.displayFormat(r) + displayFormat(r) end confirm = ask("#{I18n.t('cli.form.import.ask', :file => file)} (y/N) ").to_s @@ -286,17 +286,17 @@ class Cli case command[0] when 'display', 'show', 'd', 's' if !command[1].nil? && !command[1].empty? - self.display(command[1], group, command[2]) + display(command[1], group, command[2]) end when 'add', 'a' add() when 'update', 'u' if !command[1].nil? && !command[1].empty? - self.update(command[1]) + update(command[1]) end when 'remove', 'delete', 'r', 'd' if !command[1].nil? && !command[1].empty? - self.remove(command[1]) + remove(command[1]) end when 'group', 'g' if !command[1].nil? && !command[1].empty? diff --git a/lib/MPW.rb b/lib/MPW.rb index 1d15076..6886b85 100644 --- a/lib/MPW.rb +++ b/lib/MPW.rb @@ -115,44 +115,6 @@ class MPW return Array.new() end - # Add a new item - # @args: name -> the item name - # group -> the item group - # server -> the ip or server - # protocol -> the protocol - # login -> the login - # passwd -> the password - # port -> the port - # comment -> a comment - # @rtrn: true if it works - def add(name, group=nil, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil) - row = Array.new() - - if name.nil? || name.empty? - @error_msg = I18n.t('error.add.name_empty') - return false - end - - if port.to_i <= 0 - port = nil - end - - row[ID] = MPW.generatePassword(16) - row[PORT] = port - row[NAME] = name.force_encoding('ASCII-8BIT') - row[DATE] = Time.now.to_i - group.nil? || group.empty? ? (row[GROUP] = nil) : (row[GROUP] = group.force_encoding('ASCII-8BIT')) - server.nil? || server.empty? ? (row[SERVER] = nil) : (row[SERVER] = server.force_encoding('ASCII-8BIT')) - protocol.nil? || protocol.empty? ? (row[PROTOCOL] = nil) : (row[PROTOCOL] = protocol.force_encoding('ASCII-8BIT')) - login.nil? || login.empty? ? (row[LOGIN] = nil) : (row[LOGIN] = login.force_encoding('ASCII-8BIT')) - passwd.nil? || passwd.empty? ? (row[PASSWORD] = nil) : (row[PASSWORD] = passwd.force_encoding('ASCII-8BIT')) - comment.nil? || comment.empty? ? (row[COMMENT] = nil) : (row[COMMENT] = comment.force_encoding('ASCII-8BIT')) - - @data.push(row) - - return true - end - # Update an item # @args: id -> the item's identifiant # name -> the item name @@ -164,39 +126,49 @@ class MPW # port -> the port # comment -> a comment # @rtrn: true if the item has been updated - def update(id, name=nil, group=nil, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil) - i = 0 + def update(name, group, server, protocol, login, passwd, port, comment, id=nil) + row = Array.new() + update = false - @data.each do |row| - if row[ID] == id - - if port.to_i <= 0 - port = nil - end - - row_update = Array.new() - row_update[ID] = row[ID] - row_update[DATE] = Time.now.to_i - - name.nil? || name.empty? ? (row_update[NAME] = row[NAME]) : (row_update[NAME] = name) - group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group) - server.nil? || server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server) - protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol) - login.nil? || login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login) - passwd.nil? || passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd) - port.nil? || port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port) - comment.nil? || comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment) - - @data[i] = row_update - - return true + i = 0 + @data.each do |r| + if r[ID] == id + row = r + update = true + break end - i += 1 end - @error_msg = I18n.t('error.update.id_no_exist', :id => id) - return false + if port.to_i <= 0 + port = nil + end + + row_update = Array.new() + row_update[DATE] = Time.now.to_i + + id.nil? || id.empty? ? (row_update[ID] = MPW.generatePassword(16)) : (row_update[ID] = row[ID]) + name.nil? || name.empty? ? (row_update[NAME] = row[NAME]) : (row_update[NAME] = name) + group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group) + server.nil? || server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server) + protocol.nil? || protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol) + login.nil? || login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login) + passwd.nil? || passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd) + port.nil? || port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port) + comment.nil? || comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment) + + if row_update[NAME].nil? || row_update[NAME].empty? + @error_msg = I18n.t('error.update.name_empty') + return false + end + + if update + @data[i] = row_update + else + @data.push(row_update) + end + + return true end # Remove an item @@ -247,7 +219,7 @@ class MPW return false else row = line.parse_csv.unshift(0) - if not add(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT]) + if not update(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT]) return false end end @@ -304,7 +276,7 @@ class MPW data_remote.each do |r| if l[ID] == r[ID] if l[DATE].to_i < r[DATE].to_i - self.update(l[ID], r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT]) + update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], l[ID]) end update = true data_remote.delete_at(j) @@ -315,19 +287,18 @@ class MPW # Delete an old item if !update && l[DATE].to_i < last_update - self.remove(l[ID]) + remove(l[ID]) end end # Add item data_remote.each do |r| if r[DATE].to_i > last_update - puts 'add' - @data.push(r) + update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], r[ID]) end end - self.encrypt() + encrypt() return true end From 90086f3262d4b371ca43499f17ca09b457c97645 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:16:14 +0100 Subject: [PATCH 17/27] disable sync if connect fail --- lib/Sync.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Sync.rb b/lib/Sync.rb index 99f7d81..126b02d 100644 --- a/lib/Sync.rb +++ b/lib/Sync.rb @@ -39,6 +39,10 @@ class Sync end def get(gpg_password) + if !@sync + return nil + end + send_msg = {:action => 'get', :gpg_key => @gpg_key, :password => @password, @@ -72,6 +76,10 @@ class Sync end def update(data) + if !@sync + return true + end + send_msg = {:action => 'update', :gpg_key => @gpg_key, :password => @password, @@ -99,6 +107,10 @@ class Sync end def close() + if !@sync + return + end + send_msg = {:action => 'close'} @socket.puts send_msg.to_json end From 5d19550371975a2dce452b05c8b1f6ebeb446716 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:17:47 +0100 Subject: [PATCH 18/27] add version file --- VERSION | 1 + 1 file changed, 1 insertion(+) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3eebe6a --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.1.0 - dev From 049ad927f219e05925116424bb866d82a3c40735 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:21:45 +0100 Subject: [PATCH 19/27] update translation for MPW.rb --- i18n/en.yml | 4 +--- i18n/fr.yml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index c2203c4..a3141bf 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -1,8 +1,6 @@ --- en: error: - add: - name_empty: "You must define a name!" config: write: "Can't write the config file!" check: "Checkconfig failed!" @@ -18,7 +16,7 @@ en: bad_format: "Can't import, the file is badly formated!" read: "Can't import, unable to read %{file}!" update: - id_no_exist: "Can't update the item, the item %{id} doesn't exist!" + name_empty: "You must define a name!" cli: option: usage: "Usage" diff --git a/i18n/fr.yml b/i18n/fr.yml index a1323be..5ccef5f 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -1,8 +1,6 @@ --- fr: error: - add: - name_empty: "Vous devez définir un nom!" config: write: "Impossible d'écrire le fichier de configuration!" check: "Le fichier de configuration est invalide!" @@ -18,7 +16,7 @@ fr: bad_format: "Impossible d'importer le fichier car son format est incorrect!" read: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!" update: - id_no_exist: "Impossible de mettre à jour l'élément %{id}, car il n'existe pas!" + name_empty: "Vous devez définir un nom!" cli: option: usage: "Utilisation" From a01a28112a5280e92c4c6e995016467dfe9ce068 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:52:59 +0100 Subject: [PATCH 20/27] fix bug suffix --- lib/MPWConfig.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb index 790f34e..21c1437 100644 --- a/lib/MPWConfig.rb +++ b/lib/MPWConfig.rb @@ -112,7 +112,7 @@ class MPWConfig 'sync_host' => @sync_host, 'sync_port' => @sync_port, 'sync_pwd' => @sync_pwd, - 'sync_suffix' => @sync_uffix, + 'sync_suffix' => @sync_suffix, 'last_update' => Time.now.to_i }} begin From d5c2af0867539f1d48699d533317d981a1c8651b Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 20:55:17 +0100 Subject: [PATCH 21/27] fix bug suffix --- lib/MPWConfig.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MPWConfig.rb b/lib/MPWConfig.rb index 21c1437..d68d0c7 100644 --- a/lib/MPWConfig.rb +++ b/lib/MPWConfig.rb @@ -86,7 +86,7 @@ class MPWConfig @sync_host = config['config']['sync_host'] @sync_port = config['config']['sync_port'] @sync_pwd = config['config']['sync_pwd'] - @sync_sufix = config['config']['sync_suffix'] + @sync_suffix = config['config']['sync_suffix'] @last_update = config['config']['last_update'].to_i if @key.empty? || @file_gpg.empty? From 0598ec134f5965f2f912d69619b25bfb3b86f5ea Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 22:49:01 +0100 Subject: [PATCH 22/27] clean code --- lib/Server.rb | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/Server.rb b/lib/Server.rb index d3b561b..5b76de7 100644 --- a/lib/Server.rb +++ b/lib/Server.rb @@ -22,29 +22,29 @@ class Server loop do Thread.start(server.accept) do |client| while true do - msg = self.getClientMessage(client) + msg = getClientMessage(client) if !msg next end if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty? - self.closeConnection(client) + closeConnection(client) next end case msg['action'] when 'get' - client.puts self.getFile(msg) + client.puts getFile(msg) when 'update' - client.puts self.updateFile(msg) + client.puts updateFile(msg) when 'delete' - client.puts self.deleteFile(msg) + client.puts deleteFile(msg) when 'close' - self.closeConnection(client) + closeConnection(client) else client.puts 'Unknown command' - self.closeConnection(client) + closeConnection(client) end end end @@ -68,12 +68,10 @@ class Server salt = gpg_data['gpg']['salt'] hash = gpg_data['gpg']['hash'] data = gpg_data['gpg']['data'] - last_update = gpg_data['gpg']['last_update'] - if self.isAuthorized?(msg['password'], salt, hash) + if isAuthorized?(msg['password'], salt, hash) send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], - :last_update => last_update, :msg => 'done', :data => data} else @@ -85,7 +83,6 @@ class Server else send_msg = {:action => 'get', :gpg_key => msg['gpg_key'], - :last_update => 0, :data => '', :msg => 'fail', :error => 'file_not_exist'} @@ -126,12 +123,10 @@ class Server hash = Digest::SHA256.hexdigest(salt + msg['password']) end - if self.isAuthorized?(msg['password'], salt, hash) + if isAuthorized?(msg['password'], salt, hash) begin - last_update = Time.now.to_i config = {'gpg' => {'salt' => salt, 'hash' => hash, - 'last_update' => last_update, 'data' => data}} File.open(file_gpg, 'w+') do |file| @@ -140,7 +135,6 @@ class Server send_msg = {:action => 'update', :gpg_key => msg['gpg_key'], - :last_update => last_update, :msg => 'done'} rescue Exception => e send_msg = {:action => 'update', @@ -183,7 +177,7 @@ class Server salt = gpg_data['gpg']['salt'] hash = gpg_data['gpg']['hash'] - if self.isAuthorized?(msg['password'], salt, hash) + if isAuthorized?(msg['password'], salt, hash) begin File.unlink(file_gpg) @@ -227,8 +221,7 @@ class Server msg = client.gets return JSON.parse(msg) rescue - client.puts "Communication it's bad" - self.closeConnection(client) + closeConnection(client) return false end end From 1a9fb0795053c7a03979e1991f70ecb5353b244c Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 23:09:57 +0100 Subject: [PATCH 23/27] translate Sync.rb --- i18n/en.yml | 4 ++++ i18n/fr.yml | 4 ++++ lib/Sync.rb | 35 ++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index a3141bf..76bce2a 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -17,6 +17,10 @@ en: read: "Can't import, unable to read %{file}!" update: name_empty: "You must define a name!" + sync: + no_data: "Nothing data!" + not_authorized: "You haven't the access to remote file!" + unknown: "An unknown error is occured!" cli: option: usage: "Usage" diff --git a/i18n/fr.yml b/i18n/fr.yml index 5ccef5f..aa847ed 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -17,6 +17,10 @@ fr: read: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!" update: name_empty: "Vous devez définir un nom!" + sync: + no_data: "Aucune data!" + not_authorized: "Vous n'avez pas les autorisations d'accès au fichier distant!" + unknown: "Une erreur inconnue est survenue!" cli: option: usage: "Utilisation" diff --git a/lib/Sync.rb b/lib/Sync.rb index 126b02d..72743a3 100644 --- a/lib/Sync.rb +++ b/lib/Sync.rb @@ -14,30 +14,42 @@ class Sync attr_accessor :error_msg + # Constructor def initialize() @error_msg = nil end + # Disable the sync def disable() @sync = false end + # Connect to server + # @args: host -> the server host + # port -> ther connection port + # gpg_key -> the gpg key + # 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 - @password = password - @suffix = suffix + @gpg_key = gpg_key + @password = password + @suffix = suffix begin @socket= TCPSocket.new(host, port) @sync = true rescue Exception => e - @error_msg = "ERROR: Connection impossible\n#{e}" + @error_msg = "#{I18n.t('error.sync.connection')}\n#{e}" @sync = false end return @sync end + # Get data on server + # @args: gpg_password -> the gpg password + # @rtrn: nil if nothing data or error def get(gpg_password) if !@sync return nil @@ -51,6 +63,7 @@ class Sync @socket.puts send_msg.to_json msg = JSON.parse(@socket.gets) + puts msg case msg['error'] when nil, 'file_not_exist' tmp_file = "/tmp/mpw-#{MPW.generatePassword()}.gpg" @@ -67,14 +80,17 @@ class Sync return @mpw.search() when 'not_authorized' - @error_msg = 'not authorized' + @error_msg = "#{I18n.t('error.sync.not_authorized')}\n#{e}" else - @error_msg = 'error unknow' + @error_msg = "#{I18n.t('error.sync.unknown')}\n#{e}" end return nil end + # Update the remote data + # @args: data -> the data to send on server + # @rtrn: false if there is a problem def update(data) if !@sync return true @@ -93,11 +109,11 @@ class Sync when nil return true when 'not_authorized' - @error_msg = 'not authorized' + @error_msg = "#{I18n.t('error.sync.not_authorized')}\n#{e}" when 'no_data' - @error_msg = 'no data' + @error_msg = "#{I18n.t('error.sync.no_data')}\n#{e}" else - @error_msg = 'error unknow' + @error_msg = "#{I18n.t('error.sync.unknown')}\n#{e}" end return false @@ -106,6 +122,7 @@ class Sync def delete() end + # Close the connection def close() if !@sync return From a77266daf70d76bdcdd0be0b86ec571311b68f82 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 23:11:39 +0100 Subject: [PATCH 24/27] restruc the code --- lib/Cli.rb | 35 +++++++++++++++++++---------------- mpw | 23 ++++++++++++++++++----- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/Cli.rb b/lib/Cli.rb index ed28ca2..8e2976a 100644 --- a/lib/Cli.rb +++ b/lib/Cli.rb @@ -19,12 +19,8 @@ class Cli # Constructor # @args: lang -> the operating system language # config_file -> a specify config file - def initialize(lang, config_file=nil) - @config = MPWConfig.new(config_file) - - if not @config.checkconfig() - setup(lang) - end + def initialize(lang, config) + @config = config @mpw = MPW.new(@config.file_gpg, @config.key) if not decrypt() @@ -37,16 +33,23 @@ class Cli @sync.disable() elsif !@sync.connect(@config.sync_host, @config.sync_port, @config.key, @config.sync_pwd, @config.sync_suffix) puts "#{I18n.t('cli.sync.not_connect')}:\n#{@sync.error_msg}" - else - begin - @mpw.sync(@sync.get(@passwd), @config.last_update) - @sync.update(File.open(@config.file_gpg).read) - @config.setLastUpdate() - rescue Exception => e - puts "#{I18n.t('cli.sync.error')}:\n#{e}" - else - @sync.close() - end + end + end + + # Destructor + def finalize() + @sync.close() + end + + # Sync the data with the server + def sync() + begin + @mpw.sync(@sync.get(@passwd), @config.last_update) + @sync.update(File.open(@config.file_gpg).read) + @config.setLastUpdate() + puts @sync.error_msg + rescue Exception => e + puts "#{I18n.t('cli.sync.error')}:\n#{e}" end end diff --git a/mpw b/mpw index a313ed7..80f3344 100755 --- a/mpw +++ b/mpw @@ -93,13 +93,17 @@ OptionParser.new do |opts| end end.parse! +config = MPWConfig.new(options[:config]) +check_error = config.checkconfig() -cli = Cli.new(lang, options[:config]) +cli = Cli.new(lang, config) +cli.sync() + +# Setup a new config +if !check_error || !options[:setup].nil? + cli.setup(lang) # Display the item's informations -if not options[:setup].nil? - cli.setup() - elsif not options[:display].nil? cli.display(options[:display], options[:group], options[:type], options[:format]) @@ -125,7 +129,16 @@ elsif not options[:import].nil? # Interactive mode else - cli.interactive + begin + cli.interactive() + rescue SystemExit, Interrupt + cli.sync() + cli = nil + return 1 + end end +cli.sync() +cli = nil + exit 0 From ff15c3d6e79c809f129a58098318ec949c583566 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 23:13:59 +0100 Subject: [PATCH 25/27] add translate for Sync.rb --- i18n/en.yml | 1 + i18n/fr.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/i18n/en.yml b/i18n/en.yml index 76bce2a..933f3cd 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -18,6 +18,7 @@ en: update: name_empty: "You must define a name!" sync: + connection: "Connection fail!" no_data: "Nothing data!" not_authorized: "You haven't the access to remote file!" unknown: "An unknown error is occured!" diff --git a/i18n/fr.yml b/i18n/fr.yml index aa847ed..3423af1 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -18,6 +18,7 @@ fr: update: name_empty: "Vous devez définir un nom!" sync: + connection: "La connexion n'a pu être établie" no_data: "Aucune data!" not_authorized: "Vous n'avez pas les autorisations d'accès au fichier distant!" unknown: "Une erreur inconnue est survenue!" From e0c1f1bfc10f624ec98f4f51de5cab97060efad1 Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 23:16:49 +0100 Subject: [PATCH 26/27] add translate for Cli.rb --- i18n/en.yml | 2 ++ i18n/fr.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/i18n/en.yml b/i18n/en.yml index 933f3cd..7805f04 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -104,6 +104,8 @@ en: port: "Port" protocol: "Protocol" server: "Server" + sync: + not_connect: "The server connection fail!" ssh: option: usage: "Usage" diff --git a/i18n/fr.yml b/i18n/fr.yml index 3423af1..9005238 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -104,6 +104,8 @@ fr: port: "Port" protocol: "Protocol" server: "Serveur" + sync: + not_connect: "La connexion au serveur n'a pu être établie!" ssh: option: usage: "Utilisation" From 1298caed2e43e6d970b190bd359ad565c32cc72f Mon Sep 17 00:00:00 2001 From: nishiki Date: Wed, 15 Jan 2014 23:20:22 +0100 Subject: [PATCH 27/27] remove debug puts --- lib/Cli.rb | 1 - lib/Sync.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/Cli.rb b/lib/Cli.rb index 8e2976a..31c4a57 100644 --- a/lib/Cli.rb +++ b/lib/Cli.rb @@ -47,7 +47,6 @@ class Cli @mpw.sync(@sync.get(@passwd), @config.last_update) @sync.update(File.open(@config.file_gpg).read) @config.setLastUpdate() - puts @sync.error_msg rescue Exception => e puts "#{I18n.t('cli.sync.error')}:\n#{e}" end diff --git a/lib/Sync.rb b/lib/Sync.rb index 72743a3..0c3ed31 100644 --- a/lib/Sync.rb +++ b/lib/Sync.rb @@ -63,7 +63,6 @@ class Sync @socket.puts send_msg.to_json msg = JSON.parse(@socket.gets) - puts msg case msg['error'] when nil, 'file_not_exist' tmp_file = "/tmp/mpw-#{MPW.generatePassword()}.gpg"