1
0
Fork 0
mirror of https://github.com/nishiki/manage-password.git synced 2024-11-30 17:03:03 +00:00
mpw/lib/MPW.rb

325 lines
7.7 KiB
Ruby
Raw Normal View History

2013-07-17 20:31:28 +00:00
#!/usr/bin/ruby
# author: nishiki
# mail: nishiki@yaegashi.fr
# info: a simple script who manage your passwords
require 'rubygems'
require 'gpgme'
require 'csv'
2013-12-25 17:51:41 +00:00
require 'i18n'
2013-07-17 20:31:28 +00:00
class MPW
2013-08-31 19:57:27 +00:00
ID = 0
NAME = 1
GROUP = 2
PROTOCOL = 3
SERVER = 4
LOGIN = 5
PASSWORD = 6
PORT = 7
COMMENT = 8
2014-01-13 19:07:15 +00:00
DATE = 9
2013-07-17 20:31:28 +00:00
attr_accessor :error_msg
2014-01-11 23:37:46 +00:00
2013-07-17 20:31:28 +00:00
# Constructor
2014-01-11 23:37:46 +00:00
def initialize(file_gpg, key=nil)
@error_msg = nil
@file_gpg = file_gpg
@key = key
2013-07-17 20:31:28 +00:00
end
# Decrypt a gpg file
# @args: password -> the GPG key password
2013-08-25 08:07:39 +00:00
# @rtrn: true if data has been decrypted
2013-07-17 20:31:28 +00:00
def decrypt(passwd=nil)
2013-08-31 19:57:27 +00:00
@data = Array.new
2013-07-17 20:31:28 +00:00
begin
if File.exist?(@file_gpg)
crypto = GPGME::Crypto.new(:armor => true)
2013-08-31 19:57:27 +00:00
data_decrypt = crypto.decrypt(IO.read(@file_gpg), :password => passwd).read
data_decrypt.lines do |line|
2014-01-13 19:07:15 +00:00
@data.push(line.parse_csv)
2013-08-31 19:57:27 +00:00
end
2013-07-17 20:31:28 +00:00
end
2013-08-31 21:20:59 +00:00
2013-07-17 20:31:28 +00:00
return true
2013-09-04 20:41:56 +00:00
rescue Exception => e
2013-12-25 17:51:41 +00:00
@error_msg = "#{I18n.t('error.gpg_file.decrypt')}\n#{e}"
2013-07-17 20:31:28 +00:00
return false
end
end
# Encrypt a file
2013-08-25 08:07:39 +00:00
# @rtrn: true if the file has been encrypted
2013-07-17 20:31:28 +00:00
def encrypt()
begin
crypto = GPGME::Crypto.new(:armor => true)
file_gpg = File.open(@file_gpg, 'w+')
2013-08-31 19:57:27 +00:00
data_to_encrypt = ''
@data.each do |row|
2014-01-13 19:07:15 +00:00
data_to_encrypt << row.to_csv
2013-08-31 19:57:27 +00:00
end
crypto.encrypt(data_to_encrypt, :recipients => @key, :output => file_gpg)
2013-07-17 20:31:28 +00:00
file_gpg.close
return true
2013-09-04 20:41:56 +00:00
rescue Exception => e
2013-12-25 17:51:41 +00:00
@error_msg = "#{I18n.t('error.gpg_file.encrypt')}\n#{e}"
2013-07-17 20:31:28 +00:00
return false
end
end
# Search in some csv data
# @args: search -> the string to search
# protocol -> the connection protocol (ssh, web, other)
2013-07-17 20:31:28 +00:00
# @rtrn: a list with the resultat of the search
2014-01-14 22:00:52 +00:00
def search(search='', group=nil, protocol=nil)
2013-07-17 20:31:28 +00:00
result = Array.new()
2013-12-01 09:03:52 +00:00
if !search.nil?
search = search.downcase
end
search = search.force_encoding('ASCII-8BIT')
2013-08-31 19:57:27 +00:00
@data.each do |row|
2013-12-30 18:39:54 +00:00
row[NAME].nil? ? (name = nil) : (name = row[NAME].downcase)
row[SERVER].nil? ? (server = nil) : (server = row[SERVER].downcase)
2013-12-01 09:03:52 +00:00
row[COMMENT].nil? ? (comment = nil) : (comment = row[COMMENT].downcase)
if name =~ /^.*#{search}.*$/ || server =~ /^.*#{search}.*$/ || comment =~ /^.*#{search}.*$/
2013-09-09 19:48:42 +00:00
if (protocol.nil? || protocol.eql?(row[PROTOCOL])) && (group.nil? || group.eql?(row[GROUP]))
2013-07-17 20:31:28 +00:00
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)
2014-01-13 19:07:15 +00:00
@data.each do |row|
2014-01-14 22:00:52 +00:00
if row[ID] == id
2014-01-13 19:07:15 +00:00
return row
end
2013-07-17 20:31:28 +00:00
end
2014-01-13 19:07:15 +00:00
return Array.new()
2013-07-17 20:31:28 +00:00
end
# Update an item
# @args: id -> the item's identifiant
# name -> the item name
# group -> the item group
# server -> the ip or hostname
2013-07-17 20:31:28 +00:00
# protocol -> the protocol
# login -> the login
# passwd -> the password
# port -> the port
# comment -> a comment
# @rtrn: true if the item has been updated
2014-01-15 19:01:23 +00:00
def update(name, group, server, protocol, login, passwd, port, comment, id=nil)
row = Array.new()
update = false
i = 0
@data.each do |r|
if r[ID] == id
row = r
update = true
break
end
i += 1
end
2014-01-15 19:01:23 +00:00
if port.to_i <= 0
port = nil
end
2013-07-17 20:31:28 +00:00
2014-01-15 19:01:23 +00:00
row_update = Array.new()
row_update[DATE] = Time.now.to_i
2014-01-16 21:50:54 +00:00
id.nil? || id.empty? ? (row_update[ID] = MPW.generatePassword(16)) : (row_update[ID] = id)
2014-01-15 19:01:23 +00:00
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
2014-01-13 19:07:15 +00:00
2014-01-15 19:01:23 +00:00
if update
@data[i] = row_update
else
@data.push(row_update)
2013-07-17 20:31:28 +00:00
end
2014-01-13 19:07:15 +00:00
2014-01-15 19:01:23 +00:00
return true
2013-07-17 20:31:28 +00:00
end
# Remove an item
# @args: id -> the item's identifiant
# @rtrn: true if the item has been deleted
def remove(id)
2014-01-13 19:07:15 +00:00
i = 0
@data.each do |row|
if row[ID] == id
2014-01-14 22:00:52 +00:00
@data.delete_at(i)
2014-01-13 19:07:15 +00:00
return true
end
i += 1
2013-07-17 20:31:28 +00:00
end
2014-01-13 19:07:15 +00:00
@error_msg = I18n.t('error.delete.id_no_exist', :id => id)
return false
2013-07-17 20:31:28 +00:00
end
2013-07-25 17:51:43 +00:00
# Export to csv
# @args: file -> a string to match
# @rtrn: true if export work
def export(file)
begin
2013-08-31 19:57:27 +00:00
File.open(file, 'w+') do |file|
@data.each do |row|
2014-01-13 19:07:15 +00:00
row.delete_at(ID).delete_at(DATE)
file << row.to_csv
2013-08-31 19:57:27 +00:00
end
2013-07-25 17:51:43 +00:00
end
2013-08-31 21:20:59 +00:00
2013-07-25 17:51:43 +00:00
return true
2013-09-04 20:41:56 +00:00
rescue Exception => e
2013-12-25 17:51:41 +00:00
@error_msg = "#{I18n.t('error.export.write', :file => file)}\n#{e}"
2013-07-25 17:51:43 +00:00
return false
end
end
# Import to csv
2013-08-26 20:19:37 +00:00
# @args: file -> path to file import
2013-07-25 17:51:43 +00:00
# @rtrn: true if the import work
def import(file)
begin
data_new = IO.read(file)
data_new.lines do |line|
if not line =~ /(.*,){6}/
2013-12-25 17:51:41 +00:00
@error_msg = I18n.t('error.import.bad_format')
2013-07-25 17:51:43 +00:00
return false
2013-08-31 19:57:27 +00:00
else
row = line.parse_csv.unshift(0)
2014-01-15 19:01:23 +00:00
if not update(row[NAME], row[GROUP], row[SERVER], row[PROTOCOL], row[LOGIN], row[PASSWORD], row[PORT], row[COMMENT])
2013-08-31 19:57:27 +00:00
return false
end
2013-07-25 17:51:43 +00:00
end
end
return true
2013-09-04 20:41:56 +00:00
rescue Exception => e
2013-12-25 17:51:41 +00:00
@error_msg = "#{I18n.t('error.import.read', :file => file)}\n#{e}"
2013-07-25 17:51:43 +00:00
return false
end
end
2013-08-26 20:19:37 +00:00
2014-01-11 23:37:46 +00:00
# Return a preview import
2013-08-26 20:19:37 +00:00
# @args: file -> path to file import
# @rtrn: an array with the items to import, if there is an error return false
def importPreview(file)
begin
result = Array.new()
2013-08-31 20:14:51 +00:00
id = 0
2013-08-26 20:19:37 +00:00
data = IO.read(file)
data.lines do |line|
if not line =~ /(.*,){6}/
2013-12-25 17:51:41 +00:00
@error_msg = I18n.t('error.import.bad_format')
2013-08-26 20:19:37 +00:00
return false
else
result.push(line.parse_csv.unshift(id))
2013-08-26 20:19:37 +00:00
end
2013-08-31 20:14:51 +00:00
id += 1
2013-08-26 20:19:37 +00:00
end
return result
2013-09-04 20:41:56 +00:00
rescue Exception => e
2013-12-25 17:51:41 +00:00
@error_msg = "#{I18n.t('error.import.read', :file => file)}\n#{e}"
2013-08-26 20:19:37 +00:00
return false
end
end
2014-01-08 16:57:45 +00:00
2014-01-14 22:00:52 +00:00
# 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
2014-01-15 19:01:23 +00:00
update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], l[ID])
2014-01-14 22:00:52 +00:00
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
2014-01-15 19:01:23 +00:00
remove(l[ID])
2014-01-14 22:00:52 +00:00
end
end
# Add item
data_remote.each do |r|
if r[DATE].to_i > last_update
2014-01-15 19:01:23 +00:00
update(r[NAME], r[GROUP], r[SERVER], r[PROTOCOL], r[LOGIN], r[PASSWORD], r[PORT], r[COMMENT], r[ID])
2014-01-14 22:00:52 +00:00
end
end
2014-01-16 21:50:54 +00:00
return encrypt()
2014-01-14 22:00:52 +00:00
end
2014-01-08 16:57:45 +00:00
# Generate a random password
# @args: length -> the length password
# @rtrn: a random string
def self.generatePassword(length=8)
if length.to_i <= 0
length = 8
2014-01-09 22:16:07 +00:00
else
length = length.to_i
end
result = ''
while length > 62 do
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(62).join
length -= 62
2014-01-08 16:57:45 +00:00
end
2014-01-09 22:16:07 +00:00
result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
2014-01-08 16:57:45 +00:00
2014-01-09 22:16:07 +00:00
return result
2014-01-08 16:57:45 +00:00
end
2014-01-11 23:37:46 +00:00
2013-07-17 20:31:28 +00:00
end