From 4aa959d59125684109ffab85761522f97f2e723d Mon Sep 17 00:00:00 2001 From: nishiki Date: Fri, 10 Jan 2014 17:55:05 +0100 Subject: [PATCH] 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