mirror of
https://github.com/nishiki/manage-password.git
synced 2025-02-20 01:50:04 +00:00
first sync work :)
This commit is contained in:
parent
bc276f23c1
commit
8b86040af0
5 changed files with 248 additions and 48 deletions
19
lib/Cli.rb
19
lib/Cli.rb
|
@ -8,9 +8,11 @@ require 'highline/import'
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
require 'readline'
|
require 'readline'
|
||||||
require 'i18n'
|
require 'i18n'
|
||||||
|
require 'yaml'
|
||||||
|
|
||||||
require "#{APP_ROOT}/lib/MPW.rb"
|
require "#{APP_ROOT}/lib/MPW.rb"
|
||||||
require "#{APP_ROOT}/lib/MPWConfig.rb"
|
require "#{APP_ROOT}/lib/MPWConfig.rb"
|
||||||
|
require "#{APP_ROOT}/lib/Sync.rb"
|
||||||
|
|
||||||
class Cli
|
class Cli
|
||||||
|
|
||||||
|
@ -29,6 +31,23 @@ class Cli
|
||||||
puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
|
puts "#{I18n.t('cli.display.error')}: #{@mpw.error_msg}"
|
||||||
exit 2
|
exit 2
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# Create a new config file
|
# Create a new config file
|
||||||
|
|
58
lib/MPW.rb
58
lib/MPW.rb
|
@ -79,7 +79,7 @@ class MPW
|
||||||
# @args: search -> the string to search
|
# @args: search -> the string to search
|
||||||
# protocol -> the connection protocol (ssh, web, other)
|
# protocol -> the connection protocol (ssh, web, other)
|
||||||
# @rtrn: a list with the resultat of the search
|
# @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()
|
result = Array.new()
|
||||||
|
|
||||||
if !search.nil?
|
if !search.nil?
|
||||||
|
@ -107,7 +107,7 @@ class MPW
|
||||||
# @rtrn: a row with the resultat of the search
|
# @rtrn: a row with the resultat of the search
|
||||||
def searchById(id)
|
def searchById(id)
|
||||||
@data.each do |row|
|
@data.each do |row|
|
||||||
if @data[ID] == id
|
if row[ID] == id
|
||||||
return row
|
return row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -168,14 +168,15 @@ class MPW
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
@data.each do |row|
|
@data.each do |row|
|
||||||
if not row[ID] == id
|
if row[ID] == id
|
||||||
|
|
||||||
if port.to_i <= 0
|
if port.to_i <= 0
|
||||||
port = nil
|
port = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
row_update = Array.new()
|
row_update = Array.new()
|
||||||
row[DATE] = Time.now.to_i
|
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)
|
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)
|
group.nil? || group.empty? ? (row_update[GROUP] = row[GROUP]) : (row_update[GROUP] = group)
|
||||||
|
@ -205,7 +206,7 @@ class MPW
|
||||||
i = 0
|
i = 0
|
||||||
@data.each do |row|
|
@data.each do |row|
|
||||||
if row[ID] == id
|
if row[ID] == id
|
||||||
@data.delete(i)
|
@data.delete_at(i)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -286,6 +287,51 @@ class MPW
|
||||||
end
|
end
|
||||||
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
|
# Generate a random password
|
||||||
# @args: length -> the length password
|
# @args: length -> the length password
|
||||||
# @rtrn: a random string
|
# @rtrn: a random string
|
||||||
|
|
|
@ -15,11 +15,12 @@ class MPWConfig
|
||||||
attr_accessor :lang
|
attr_accessor :lang
|
||||||
attr_accessor :file_gpg
|
attr_accessor :file_gpg
|
||||||
attr_accessor :timeout_pwd
|
attr_accessor :timeout_pwd
|
||||||
|
attr_accessor :last_update
|
||||||
attr_accessor :sync_host
|
attr_accessor :sync_host
|
||||||
attr_accessor :sync_port
|
attr_accessor :sync_port
|
||||||
attr_accessor :sync_pwd
|
attr_accessor :sync_pwd
|
||||||
attr_accessor :sync_sufix
|
attr_accessor :sync_suffix
|
||||||
attr_accessor :sync_last_update
|
attr_accessor :last_update
|
||||||
|
|
||||||
# Constructor
|
# Constructor
|
||||||
# @args: file_config -> the specify config file
|
# @args: file_config -> the specify config file
|
||||||
|
@ -78,15 +79,15 @@ class MPWConfig
|
||||||
def checkconfig()
|
def checkconfig()
|
||||||
begin
|
begin
|
||||||
config = YAML::load_file(@file_config)
|
config = YAML::load_file(@file_config)
|
||||||
@key = config['config']['key']
|
@key = config['config']['key']
|
||||||
@lang = config['config']['lang']
|
@lang = config['config']['lang']
|
||||||
@file_gpg = config['config']['file_gpg']
|
@file_gpg = config['config']['file_gpg']
|
||||||
@timeout_pwd = config['config']['timeout_pwd'].to_i
|
@timeout_pwd = config['config']['timeout_pwd'].to_i
|
||||||
@sync_host = config['config']['sync_host']
|
@sync_host = config['config']['sync_host']
|
||||||
@sync_port = config['config']['sync_port']
|
@sync_port = config['config']['sync_port']
|
||||||
@sync_pwd = config['config']['sync_pwd']
|
@sync_pwd = config['config']['sync_pwd']
|
||||||
@sync_sufix = config['config']['sync_suffix']
|
@sync_sufix = config['config']['sync_suffix']
|
||||||
@sync_last_update = config['config']['sync_last_update'].to_i
|
@last_update = config['config']['last_update'].to_i
|
||||||
|
|
||||||
if @key.empty? || @file_gpg.empty?
|
if @key.empty? || @file_gpg.empty?
|
||||||
@error_msg = I18n.t('error.config.check')
|
@error_msg = I18n.t('error.config.check')
|
||||||
|
@ -102,5 +103,28 @@ class MPWConfig
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -21,29 +21,33 @@ class Server
|
||||||
server = TCPServer.open(@host, @port)
|
server = TCPServer.open(@host, @port)
|
||||||
loop do
|
loop do
|
||||||
Thread.start(server.accept) do |client|
|
Thread.start(server.accept) do |client|
|
||||||
msg = self.getClientMessage(client)
|
while true do
|
||||||
|
msg = self.getClientMessage(client)
|
||||||
|
|
||||||
if !msg
|
if !msg
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty?
|
if msg['gpg_key'].nil? || msg['gpg_key'].empty? || msg['password'].nil? || msg['password'].empty?
|
||||||
self.closeConnection(client)
|
self.closeConnection(client)
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
case msg['action']
|
case msg['action']
|
||||||
when 'get'
|
when 'get'
|
||||||
client.puts self.getFile(msg)
|
client.puts self.getFile(msg)
|
||||||
when 'update'
|
when 'update'
|
||||||
client.puts self.updateFile(msg)
|
client.puts self.updateFile(msg)
|
||||||
when 'delete'
|
puts 'update'
|
||||||
client.puts self.deleteFile(msg)
|
when 'delete'
|
||||||
else
|
client.puts self.deleteFile(msg)
|
||||||
client.puts 'Unknown command'
|
when 'close'
|
||||||
|
self.closeConnection(client)
|
||||||
|
else
|
||||||
|
client.puts 'Unknown command'
|
||||||
|
self.closeConnection(client)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.closeConnection(client)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -68,11 +72,11 @@ class Server
|
||||||
last_update = gpg_data['gpg']['last_update']
|
last_update = gpg_data['gpg']['last_update']
|
||||||
|
|
||||||
if self.isAuthorized?(msg['password'], salt, hash)
|
if self.isAuthorized?(msg['password'], salt, hash)
|
||||||
send_msg = {:action => 'get',
|
send_msg = {:action => 'get',
|
||||||
:gpg_key => msg['gpg_key'],
|
:gpg_key => msg['gpg_key'],
|
||||||
:last_update => last_update,
|
:last_update => last_update,
|
||||||
:msg => 'done',
|
:msg => 'done',
|
||||||
:data => data}
|
:data => data}
|
||||||
else
|
else
|
||||||
send_msg = {:action => 'get',
|
send_msg = {:action => 'get',
|
||||||
:gpg_key => msg['gpg_key'],
|
:gpg_key => msg['gpg_key'],
|
||||||
|
@ -80,10 +84,12 @@ class Server
|
||||||
:error => 'not_authorized'}
|
:error => 'not_authorized'}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
send_msg = {:action => 'get',
|
send_msg = {:action => 'get',
|
||||||
:gpg_key => msg['gpg_key'],
|
:gpg_key => msg['gpg_key'],
|
||||||
:msg => 'fail',
|
:last_update => 0,
|
||||||
:error => 'file_not_exist'}
|
:data => '',
|
||||||
|
:msg => 'fail',
|
||||||
|
:error => 'file_not_exist'}
|
||||||
end
|
end
|
||||||
|
|
||||||
return send_msg.to_json
|
return send_msg.to_json
|
||||||
|
@ -129,7 +135,7 @@ class Server
|
||||||
'last_update' => last_update,
|
'last_update' => last_update,
|
||||||
'data' => data}}
|
'data' => data}}
|
||||||
|
|
||||||
File.open(file_gpg, 'w') do |file|
|
File.open(file_gpg, 'w+') do |file|
|
||||||
file << config.to_yaml
|
file << config.to_yaml
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -242,11 +248,11 @@ class Server
|
||||||
begin
|
begin
|
||||||
config = YAML::load_file(file_config)
|
config = YAML::load_file(file_config)
|
||||||
@host = config['config']['host']
|
@host = config['config']['host']
|
||||||
@port = config['config']['port']
|
@port = config['config']['port'].to_i
|
||||||
@data_dir = config['config']['data_dir']
|
@data_dir = config['config']['data_dir']
|
||||||
@timeout = config['config']['timeout'].to_i
|
@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.fail')
|
||||||
puts I18n.t('server.checkconfig.empty')
|
puts I18n.t('server.checkconfig.empty')
|
||||||
return false
|
return false
|
||||||
|
|
105
lib/Sync.rb
Normal file
105
lib/Sync.rb
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue