1
0
Fork 0
mirror of https://github.com/nishiki/manage-password.git synced 2025-02-20 01:50:04 +00:00

separate cli and class

This commit is contained in:
nishiki 2013-07-17 22:31:28 +02:00
parent 1f7c177eea
commit 13238d8d6b
4 changed files with 430 additions and 304 deletions

310
MPW.rb Executable file
View file

@ -0,0 +1,310 @@
#!/usr/bin/ruby
# author: nishiki
# mail: nishiki@yaegashi.fr
# info: a simple script who manage your passwords
require 'rubygems'
require 'gpgme'
require 'csv'
require 'net/ssh'
require 'yaml'
class MPW
ID = 0
PROTOCOL = 1
SERVER = 2
LOGIN = 3
PASSWORD = 4
PORT = 5
COMMENT = 6
attr_accessor :error
attr_accessor :error_msg
# Constructor
def initialize()
@file_config = "#{Dir.home()}/.mpw.cfg"
@error_mgs = nil
@error = 0
end
# Create a new config file
# @args: key -> the gpg key to encrypt
# 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, file_gpg, file_pwd, timeout_pwd)
if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/
@error_msg = "The key string isn't in good format!"
@error = 1
return false
end
if file_gpg.empty?
file_gpg = "#{Dir.home()}/.mpw.gpg"
end
if file_pwd.empty?
file_pwd = "#{Dir.home()}/.mpw.pwd"
end
timeout_pwd.empty? ? (timeout_pwd = 300) : (timeout_pwd = timeout_pwd.to_i)
config = {'config' => {'key' => key,
'file_gpg' => file_gpg,
'timeout_pwd' => timeout_pwd,
'file_pwd' => file_pwd}}
begin
File.open(@file_config, 'w') do |file|
file << config.to_yaml
end
rescue
@error_msg = "Can't write the config file!"
@error = 2
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']
@file_gpg = config['config']['file_gpg']
@file_pwd = config['config']['file_pwd']
@timeout_pwd = config['config']['timeout_pwd'].to_i
if @key.empty? || @file_gpg.empty? || @file_pwd.empty?
return false
end
rescue
@error_msg = "Checkconfig failed!"
@error = 3
return false
end
return true
end
# Decrypt a gpg file
# @args: password -> the GPG key password
# @rtrn: true if data is decrypted
def decrypt(passwd=nil)
@data = ""
begin
if passwd.nil?
passwd = IO.read(@file_pwd)
end
rescue
if not passwd.nil?
file_pwd = File.new(@file_pwd, 'w')
File.chmod(0600, @file_pwd)
file_pwd << passwd
file_pwd.close
end
end
begin
if File.exist?(@file_gpg)
crypto = GPGME::Crypto.new(:armor => true)
@data = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read
end
return true
rescue
if not @file_pwd.nil?
File.delete(@file_pwd)
end
@error_msg = "Can't decrypt file!"
@error = 4
return false
end
end
# Check if a password it saved
# @rtrn: true if a password exist in the password file
def checkFilePassword()
if !@file_pwd.nil? && File.exist?(@file_pwd) && File.stat(@file_pwd).mtime.to_i + @timeout_pwd < Time.now.to_i
File.delete(@file_pwd)
return false
end
return true
end
# Encrypt a file
def encrypt()
begin
crypto = GPGME::Crypto.new(:armor => true)
file_gpg = File.open(@file_gpg, 'w+')
crypto.encrypt(@data, :recipients => @key, :output => file_gpg)
file_gpg.close
return true
rescue
@error_msg = "Can't encrypt the GPG file!"
@error = 5
return false
end
end
# Search in some csv data
# @args: search -> the string to search
# type -> the connection type (ssh, web, other)
# @rtrn: a list with the resultat of the search
def search(search, protocol=nil)
result = Array.new()
@data.lines do |line|
row = line.parse_csv
if line =~ /^.*#{search}.*$/ || protocol.eql?('all')
if protocol.nil? || protocol.eql?(row[PROTOCOL]) || protocol.eql?('all')
result.push(row)
end
end
end
return result
end
# Search in some csv data
# @args: id -> the id item
# @rtrn: a row with the resultat of the search
def searchById(id)
@data.lines do |line|
row = line.parse_csv
if !id.nil? && id.eql?(row[ID])
return row
end
end
return Array.new()
end
# Add a new item
# @args: server -> the ip or server
# protocol -> the protocol
# login -> the login
# passwd -> the password
# port -> the port
# comment -> a comment
def add(server, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil)
row = Array.new()
row[ID] = Time.now.to_i.to_s(16)
row[SERVER] = server
row[PROTOCOL] = protocol
row[LOGIN] = login
row[PASSWORD] = passwd
row[PORT] = port
row[COMMENT] = comment
@data << "#{row.join(',')}\n"
end
# Update an item
# @args: id -> the item's identifiant
# server -> the ip or server
# protocol -> the protocol
# login -> the login
# passwd -> the password
# port -> the port
# comment -> a comment
# @rtrn: true if the item has been updated
def update(id, server=nil, protocol=nil, login=nil, passwd=nil, port=nil, comment=nil)
updated = false
data_tmp = ''
@data.lines do |line|
row = line.parse_csv
if id.eql?(row[ID])
row_update = Array.new()
row_update[ID] = row[ID]
server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server)
protocol.empty? ? (row_update[PROTOCOL] = row[PROTOCOL]) : (row_update[PROTOCOL] = protocol)
login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login)
passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd)
port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port)
comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment)
data_tmp << "#{row_update.join(',')}\n"
updated = true
else
data_tmp << line
end
end
@data = data_tmp
if not updated
@error_msg = "Can't update the item: #{id}!"
@error = 6
end
return updated
end
# Remove an item
# @args: id -> the item's identifiant
# @rtrn: true if the item has been deleted
def remove(id)
removed = false
data_tmp = ""
@data.lines do |line|
row = line.parse_csv
if id.eql?(row[ID])
removed = true
else
data_tmp << line
end
end
@data = data_tmp
if not removed
@error_msg = "Can't remove the item: #{id}!"
@error = 7
end
return removed
end
# Connect to ssh && display the password
# @args: search -> a string to match
# @rtrn: true if ssh connection work
def ssh(search)
result = self.search(search, 'ssh')
if result.length > 0
result.each do |r|
server = r[SERVER]
login = r[LOGIN]
port = r[PORT]
passwd = r[PASSWORD]
if port.empty?
port = 22
end
if passwd.empty?
system("#{passwd} ssh #{login}@#{server} -p #{port}")
else
system("sshpass -p #{passwd} ssh #{login}@#{server} -p #{port}")
end
end
return true
else
return false
end
end
end

154
cli.rb
View file

@ -1,28 +1,24 @@
#!/usr/bin/ruby
# author: nishiki
# mail: nishiki@yaegashi.fr
# info: a simple script who manage your passwords
# info: a simple script who m your passwords
require 'rubygems'
require 'highline/import'
require 'yaml'
require './MPW.rb'
class Cli
attr_accessor :key
attr_accessor :file_gpg
attr_accessor :file_pwd
attr_accessor :timeout_pwd
def initialize()
@file_config = "#{Dir.home()}/.mpw.cfg"
if !File.exist?(@file_config) || !self.checkconfig()
@m = MPW.new()
if not @m.checkconfig()
self.setup()
if not self.checkconfig()
puts "Error during the checkconfig post setup!"
exit 2
end
end
if not self.decrypt()
puts "ERROR: #{@m.error_msg}"
exit 2
end
end
@ -32,50 +28,102 @@ class Cli
file_gpg = ask("Enter the path to encrypt file [default=#{Dir.home()}/.mpw.gpg]: ")
file_pwd = ask("Enter te path to password file [default=#{Dir.home()}/.mpw.pwd]: ")
timeout_pwd = ask("Enter the timeout (in seconde) to GPG password [default=300]: ")
if not key =~ /[a-zA-Z0-9.-_]*\@[a-zA-Z0-9]*\.[a-zA-Z]*/
puts "GPG key is invalid!"
exit 2
end
if file_gpg.empty?
file_gpg = "#{Dir.home()}/.mpw.gpg"
end
if file_pwd.empty?
file_pwd = "#{Dir.home()}/.mpw.pwd"
end
timeout_pwd.empty? ? (timeout_pwd = 300) : (timeout_pwd = timeout_pwd.to_i)
config = {'config' => {'key' => key,
'file_gpg' => file_gpg,
'timeout_pwd' => timeout_pwd,
'file_pwd' => file_pwd}}
File.open(@file_config, 'w') do |file|
file << config.to_yaml
if setup(key, file_gpg, file_pwd, timeout_pwd)
puts "The config file has been created!"
else
puts "ERROR: #{@m.error_msg}"
end
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']
@file_gpg = config['config']['file_gpg']
@file_pwd = config['config']['file_pwd']
@timeout_pwd = config['config']['timeout_pwd'].to_i
if @key.empty? || @file_gpg.empty? || @file_pwd.empty?
return false
end
rescue
return false
def decrypt()
if not @m.checkFilePassword()
passwd = ask("Password GPG: ") {|q| q.echo = false}
return @m.decrypt(passwd)
else
return @m.decrypt()
end
end
return true
def display(search, protocol=nil)
result = @m.search(search, protocol)
if not result.empty?
result.each do |r|
puts "# --------------------"
puts "# Id: #{r[MPW::ID]}"
puts "# Server: #{r[MPW::SERVER]}"
puts "# Type: #{r[MPW::PROTOCOL]}"
puts "# Login: #{r[MPW::LOGIN]}"
puts "# Password: #{r[MPW::PASSWORD]}"
puts "# Port: #{r[MPW::PORT]}"
puts "# Comment: #{r[MPW::COMMENT]}"
end
else
puts "Nothing result!"
end
end
def add()
row = Array.new()
puts "# Add a new item"
puts "# --------------------"
server = ask("Enter the server name or ip: ")
protocol = ask("Enter the type of connection (ssh, web, other): ")
login = ask("Enter the login connection: ")
passwd = ask("Enter the the password: ")
port = ask("Enter the connection port (optinal): ")
comment = ask("Enter a comment (optinal): ")
@m.add(server, protocol, login, passwd, port, comment)
if @m.encrypt()
puts "Item has been added!"
else
puts "ERROR: #{@m.error_msg}"
end
end
def update(id)
row = @m.searchById(id)
if not row.empty?
puts "# Add a new password"
puts "# --------------------"
server = ask("Enter the server name or ip [#{row[MPW::SERVER]}]: ")
protocol = ask("Enter the type of connection [#{row[MPW::PROTOCOL]}]: ")
login = ask("Enter the login connection [#{row[MPW::LOGIN]}]: ")
passwd = ask("Enter the the password: ")
port = ask("Enter the connection port [#{row[MPW::PORT]}]: ")
comment = ask("Enter a comment [#{row[MPW::COMMENT]}]: ")
if @m.update(id, server, protocol, login, passwd, port, comment)
if @m.encrypt()
puts "Item has been updated!"
else
puts "ERROR: #{@m.error_msg}"
end
else
puts "Nothing item has been updated!"
end
else
puts "Nothing result!"
end
end
def remove(id)
if @m.remove(id)
if @m.encrypt()
puts "The item #{id} has been removed!"
else
puts "ERROR: #{@m.error_msg}"
end
else
puts "Nothing item has been removed!"
end
end
def ssh(search)
@m.ssh(search)
end
end

View file

@ -1,235 +0,0 @@
#!/usr/bin/ruby
# author: nishiki
# mail: nishiki@yaegashi.fr
# info: a simple script who manage your passwords
require 'rubygems'
require 'gpgme'
require 'csv'
require 'net/ssh'
require 'highline/import'
class ManagePasswd
ID = 0
TYPE = 1
SERVER = 2
LOGIN = 3
PASSWORD = 4
PORT = 5
COMMENT = 6
# Constructor
# @args: key -> the gpg key to encrypt
# file_gpg -> the file who is encrypted
# file_pwd -> the file who stock the password
# timeout_pwd -> time to save the password
def initialize(key, file_gpg, file_pwd, timeout_pwd=300)
@key = key
@file_gpg = file_gpg
@file_pwd = file_pwd
@timeout_pwd = timeout_pwd
if File.exist?(@file_gpg)
if not self.decrypt()
exit 2
end
else
@data = ""
end
end
# Decrypt a gpg file
# @rtrn: true if data is decrypted
def decrypt()
if File.exist?(@file_pwd) && File.stat(@file_pwd).mtime.to_i + @timeout_pwd < Time.now.to_i
File.delete(@file_pwd)
end
begin
passwd = IO.read(@file_pwd)
rescue
passwd = ask("Password GPG: ") {|q| q.echo = false}
file_pwd = File.new(@file_pwd, 'w+')
File.chmod(0600, @file_pwd)
file_pwd << passwd
file_pwd.close
end
begin
crypto = GPGME::Crypto.new(:armor => true)
@data = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read
return true
rescue
puts "Your passphrase is probably wrong!"
File.delete(@file_pwd)
return false
end
end
# Encrypt a file
def encrypt()
begin
crypto = GPGME::Crypto.new(:armor => true)
file_gpg = File.open(@file_gpg, 'w+')
crypto.encrypt(@data, :recipients => @key, :output => file_gpg)
file_gpg.close
return true
rescue
puts "Error during the encrypting file"
return false
end
end
# Search in some csv data
# @args: search -> the string to search
# type -> the connection type (ssh, web, other)
# @rtrn: a list with the resultat of the search
def search(search, type=nil)
result = Array.new()
@data.lines do |line|
row = line.parse_csv
if line =~ /^.*#{search}.*$/ || type.eql?('all')
if type.nil? || type.eql?(row[TYPE]) || type.eql?('all')
result.push(row)
end
end
end
return result
end
# Display the connections informations for a server
# @args: search -> a string to match
# type -> search for a type item
def display(search, type=nil)
result = self.search(search, type)
if result.length > 0
result.each do |r|
puts "# --------------------"
puts "# Id: #{r[ID]}"
puts "# Server: #{r[SERVER]}"
puts "# Type: #{r[TYPE]}"
puts "# Login: #{r[LOGIN]}"
puts "# Password: #{r[PASSWORD]}"
puts "# Port: #{r[PORT]}"
puts "# Comment: #{r[COMMENT]}"
end
return true
else
puts "Nothing result!"
return false
end
end
# Add a new item
def add()
row = Array.new()
puts "# Add a new password"
puts "# --------------------"
row[ID] = Time.now.to_i.to_s(16)
row[SERVER] = ask("Enter the server name or ip: ")
row[TYPE] = ask("Enter the type of connection (ssh, web, other): ")
row[LOGIN] = ask("Enter the login connection: ")
row[PASSWORD] = ask("Enter the the password: ")
row[PORT] = ask("Enter the connection port (optinal): ")
row[COMMENT] = ask("Enter a comment (optinal): ")
@data << "#{row.join(',')}\n"
puts 'Item has been added!'
end
# Update an item
# @args: id -> the item's identifiant
def update(id)
data_tmp = ''
@data.lines do |line|
row = line.parse_csv
if id.eql?(row[ID])
row_update = Array.new()
puts "# Add a new password"
puts "# --------------------"
server = ask("Enter the server name or ip [#{row[SERVER]}]: ")
type = ask("Enter the type of connection [#{row[TYPE]}]: ")
login = ask("Enter the login connection [#{row[LOGIN]}]: ")
passwd = ask("Enter the the password: ")
port = ask("Enter the connection port [#{row[PORT]}]: ")
comment = ask("Enter a comment [#{row[COMMENT]}]: ")
row_update[ID] = row[ID]
server.empty? ? (row_update[SERVER] = row[SERVER]) : (row_update[SERVER] = server)
type.empty? ? (row_update[TYPE] = row[TYPE]) : (row_update[TYPE] = type)
login.empty? ? (row_update[LOGIN] = row[LOGIN]) : (row_update[LOGIN] = login)
passwd.empty? ? (row_update[PASSWORD] = row[PASSWORD]) : (row_update[PASSWORD] = passwd)
port.empty? ? (row_update[PORT] = row[PORT]) : (row_update[PORT] = port)
comment.empty? ? (row_update[COMMENT] = row[COMMENT]) : (row_update[COMMENT] = comment)
data_tmp << "#{row_update.join(',')}\n"
else
data_tmp << line
end
end
@data = data_tmp
puts 'Item has been updated!'
end
# Remove an item
# @args: id -> the item's identifiant
def remove(id)
data_tmp = ''
@data.lines do |line|
row = line.parse_csv
if id.eql?(row[ID])
puts "The item #{row[ID]} has been removed!"
else
data_tmp << line
end
end
@data = data_tmp
end
# Connect to ssh && display the password
# @args: search -> a string to match
def ssh(search)
result = self.search(search, 'ssh')
if result.length > 0
result.each do |r|
server = r[SERVER]
login = r[LOGIN]
port = r[PORT]
passwd = r[PASSWORD]
if port.empty?
port = 22
end
if passwd.empty?
system("#{passwd} ssh #{login}@#{server} -p #{port}")
else
system("sshpass -p #{passwd} ssh #{login}@#{server} -p #{port}")
end
#Net::SSH.start(server, login, :port => port, :password => passwd) do |ssh|
# channel = ssh.open_channel do |ch|
# puts ch.exec 'ls'
# ch.on_data do |data|
# $stdout.print data
# end
# end
#end
end
return true
else
puts "Nothing result!"
return false
end
end
end

35
mpw
View file

@ -5,12 +5,11 @@
require 'rubygems'
require 'optparse'
require './manage-password.rb'
require './cli.rb'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: manage-password.rb [options]"
opts.banner = "Usage: mpw [options]"
opts.on("-d", "--display [SEARCH]", "Display items") do |search|
search.nil? ? (options[:display] = '') : (options[:display] = search)
@ -33,48 +32,52 @@ OptionParser.new do |opts|
options[:add] = true
end
opts.on("-t", "--type TYPE", "select an type") do |type|
opts.on("-s", "--ssh SEARCH", "Connect to ssh") do |search|
options[:ssh] = search
end
opts.on("-p", "--protocol PROTOCOL", "Select a protocol") do |type|
options[:type] = type
end
opts.on("-f", "--force", "Force an action") do |b|
options[:force] = true
end
opts.on("-h", "--help", "Show this message") do |b|
puts opts
exit 0
end
end.parse!
cli = Cli.new
manage = ManagePasswd.new(cli.key, cli.file_gpg, cli.file_pwd)
cli = Cli.new()
puts options
# Display the item's informations
if not options[:display].nil?
if not options[:type].nil?
manage.display(options[:display], options[:type])
cli.display(options[:display], options[:type])
elsif not options[:showall].nil?
manage.display(options[:display], 'all')
cli.display(options[:display], 'all')
else
manage.display(options[:display])
cli.display(options[:display])
end
# Remove an item
elsif not options[:remove].nil?
manage.remove(options[:remove])
manage.encrypt()
cli.remove(options[:remove])
# Update an item
elsif not options[:update].nil?
manage.update(options[:update])
manage.encrypt()
cli.update(options[:update])
# Connect to ssh
elsif not options[:ssh].nil?
manage.ssh(options[:ssh])
cli.ssh(options[:ssh])
# Add a new item
elsif not options[:add].nil?
manage.add()
manage.encrypt()
cli.add()
else
puts "For help add option -h or --help"