mpw 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mpw/item.rb ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/ruby
2
+ # author: nishiki
3
+ # mail: nishiki@yaegashi.fr
4
+
5
+ require 'rubygems'
6
+ require 'i18n'
7
+
8
+ module MPW
9
+ class Item
10
+
11
+ attr_accessor :error_msg
12
+
13
+ attr_accessor :id
14
+ attr_accessor :name
15
+ attr_accessor :group
16
+ attr_accessor :host
17
+ attr_accessor :protocol
18
+ attr_accessor :user
19
+ attr_accessor :password
20
+ attr_accessor :port
21
+ attr_accessor :comment
22
+ attr_accessor :last_edit
23
+ attr_accessor :last_sync
24
+ attr_accessor :created
25
+
26
+ # Constructor
27
+ # Create a new item
28
+ # @args: options -> a hash of parameter
29
+ # raise an error if the hash hasn't the key name
30
+ def initialize(options={})
31
+ if not options.has_key?(:name) or options[:name].to_s.empty?
32
+ @error_msg = I18n.t('error.update.name_empty')
33
+ raise @error_msg
34
+ end
35
+
36
+ if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty?
37
+ @id = generate_id
38
+ @created = Time.now.to_i
39
+ else
40
+ @id = options[:id]
41
+ @created = options[:created]
42
+ @last_edit = options[:last_edit]
43
+ options[:no_update_last_edit] = true
44
+ end
45
+
46
+ update(options)
47
+ end
48
+
49
+ # Update the item
50
+ # @args: options -> a hash of parameter
51
+ # @rtrn: true if the item is update
52
+ def update(options={})
53
+ if options.has_key?(:name) and options[:name].to_s.empty?
54
+ @error_msg = I18n.t('error.update.name_empty')
55
+ return false
56
+ end
57
+
58
+ @name = options[:name] if options.has_key?(:name)
59
+ @group = options[:group] if options.has_key?(:group)
60
+ @host = options[:host] if options.has_key?(:host)
61
+ @protocol = options[:protocol] if options.has_key?(:protocol)
62
+ @user = options[:user] if options.has_key?(:user)
63
+ @password = options[:password] if options.has_key?(:password)
64
+ @port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty?
65
+ @comment = options[:comment] if options.has_key?(:comment)
66
+ @last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit)
67
+
68
+ return true
69
+ end
70
+
71
+ # Update last_sync
72
+ def set_last_sync
73
+ @last_sync = Time.now.to_i
74
+ end
75
+
76
+ # Delete all data
77
+ # @rtrn: true
78
+ def delete
79
+ @id = nil
80
+ @name = nil
81
+ @group = nil
82
+ @host = nil
83
+ @protocol = nil
84
+ @user = nil
85
+ @password = nil
86
+ @port = nil
87
+ @comment = nil
88
+ @created = nil
89
+ @last_edit = nil
90
+ @last_sync = nil
91
+
92
+ return true
93
+ end
94
+
95
+ def empty?
96
+ return @name.to_s.empty?
97
+ end
98
+
99
+ def nil?
100
+ return false
101
+ end
102
+
103
+ # Generate an random id
104
+ private
105
+ def generate_id
106
+ return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join
107
+ end
108
+ end
109
+ end
data/lib/mpw/mpw.rb ADDED
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/ruby
2
+ # author: nishiki
3
+ # mail: nishiki@yaegashi.fr
4
+
5
+ require 'rubygems'
6
+ require 'gpgme'
7
+ require 'csv'
8
+ require 'i18n'
9
+ require 'fileutils'
10
+ require 'yaml'
11
+ require 'mpw/item'
12
+
13
+ module MPW
14
+ class MPW
15
+
16
+ attr_accessor :error_msg
17
+
18
+ # Constructor
19
+ def initialize(file_gpg, key, share_keys='')
20
+ @error_msg = nil
21
+ @file_gpg = file_gpg
22
+ @key = key
23
+ @share_keys = share_keys
24
+ @data = []
25
+ end
26
+
27
+ # Decrypt a gpg file
28
+ # @args: password -> the GPG key password
29
+ # @rtrn: true if data has been decrypted
30
+ def decrypt(password=nil)
31
+ @data = []
32
+
33
+ if File.exist?(@file_gpg) and not File.zero?(@file_gpg)
34
+ crypto = GPGME::Crypto.new(armor: true)
35
+ data_decrypt = crypto.decrypt(IO.read(@file_gpg), password: password).read.force_encoding('utf-8')
36
+
37
+ if not data_decrypt.to_s.empty?
38
+ YAML.load(data_decrypt).each_value do |d|
39
+ @data.push(Item.new(id: d['id'],
40
+ name: d['name'],
41
+ group: d['group'],
42
+ host: d['host'],
43
+ protocol: d['protocol'],
44
+ user: d['user'],
45
+ password: d['password'],
46
+ port: d['port'],
47
+ comment: d['comment'],
48
+ last_edit: d['last_edit'],
49
+ created: d['created'],
50
+ )
51
+ )
52
+ end
53
+ end
54
+ end
55
+
56
+ return true
57
+ rescue Exception => e
58
+ @error_msg = "#{I18n.t('error.gpg_file.decrypt')}\n#{e}"
59
+ return false
60
+ end
61
+
62
+ # Encrypt a file
63
+ # @rtrn: true if the file has been encrypted
64
+ def encrypt
65
+ FileUtils.cp(@file_gpg, "#{@file_gpg}.bk") if File.exist?(@file_gpg)
66
+
67
+ data_to_encrypt = {}
68
+
69
+ @data.each do |item|
70
+ next if item.empty?
71
+
72
+ data_to_encrypt.merge!(item.id => {'id' => item.id,
73
+ 'name' => item.name,
74
+ 'group' => item.group,
75
+ 'host' => item.host,
76
+ 'protocol' => item.protocol,
77
+ 'user' => item.user,
78
+ 'password' => item.password,
79
+ 'port' => item.port,
80
+ 'comment' => item.comment,
81
+ 'last_edit' => item.last_edit,
82
+ 'created' => item.created,
83
+ }
84
+ )
85
+ end
86
+
87
+ recipients = []
88
+ recipients.push(@key)
89
+ if not @share_keys.nil?
90
+ @share_keys.split.each { |k| recipients.push(k) }
91
+ end
92
+
93
+ crypto = GPGME::Crypto.new(armor: true)
94
+ file_gpg = File.open(@file_gpg, 'w+')
95
+ crypto.encrypt(data_to_encrypt.to_yaml, recipients: recipients, output: file_gpg)
96
+ file_gpg.close
97
+
98
+ FileUtils.rm("#{@file_gpg}.bk") if File.exist?("#{@file_gpg}.bk")
99
+ return true
100
+ rescue Exception => e
101
+ @error_msg = "#{I18n.t('error.gpg_file.encrypt')}\n#{e}"
102
+ FileUtils.mv("#{@file_gpg}.bk", @file_gpg) if File.exist?("#{@file_gpg}.bk")
103
+ return false
104
+ end
105
+
106
+ # Add a new item
107
+ # @args: item -> Object MPW::Item
108
+ # @rtrn: true if add item
109
+ def add(item)
110
+ if not item.instance_of?(Item)
111
+ @error_msg = I18n.t('error.bad_class')
112
+ return false
113
+ elsif item.empty?
114
+ @error_msg = I18n.t('error.add.empty')
115
+ return false
116
+ else
117
+ @data.push(item)
118
+ return true
119
+ end
120
+ end
121
+
122
+ # Search in some csv data
123
+ # @args: options -> a hash with paramaters
124
+ # @rtrn: a list with the resultat of the search
125
+ def list(options={})
126
+ result = []
127
+
128
+ search = options[:search].to_s.downcase
129
+ group = options[:group].to_s.downcase
130
+ protocol = options[:protocol].to_s.downcase
131
+
132
+ @data.each do |item|
133
+ next if item.empty?
134
+
135
+ next if not group.empty? and not group.eql?(item.group.downcase)
136
+ next if not protocol.empty? and not protocol.eql?(item.protocol.downcase)
137
+
138
+ name = item.name.to_s.downcase
139
+ host = item.host.to_s.downcase
140
+ comment = item.comment.to_s.downcase
141
+
142
+ if not name =~ /^.*#{search}.*$/ and not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/
143
+ next
144
+ end
145
+
146
+ result.push(item)
147
+ end
148
+
149
+ return result
150
+ end
151
+
152
+ # Search in some csv data
153
+ # @args: id -> the id item
154
+ # @rtrn: a row with the result of the search
155
+ def search_by_id(id)
156
+ @data.each do |item|
157
+ return item if item.id == id
158
+ end
159
+
160
+ return nil
161
+ end
162
+
163
+ # Export to csv
164
+ # @args: file -> file where you export the data
165
+ # type -> udata type
166
+ # @rtrn: true if export work
167
+ def export(file, type=:yaml)
168
+ case type
169
+ when :csv
170
+ CSV.open(file, 'w', write_headers: true,
171
+ headers: ['name', 'group', 'protocol', 'host', 'user', 'password', 'port', 'comment']) do |csv|
172
+ @data.each do |item|
173
+ csv << [item.name, item.group, item.protocol, item.host, item.user, item.password, item.port, item.comment]
174
+ end
175
+ end
176
+
177
+ when :yaml
178
+ data = {}
179
+ @data.each do |item|
180
+ data.merge!(item.id => {'id' => item.id,
181
+ 'name' => item.name,
182
+ 'group' => item.group,
183
+ 'host' => item.host,
184
+ 'protocol' => item.protocol,
185
+ 'user' => item.user,
186
+ 'password' => item.password,
187
+ 'port' => item.port,
188
+ 'comment' => item.comment,
189
+ 'last_edit' => item.last_edit,
190
+ 'created' => item.created,
191
+ }
192
+ )
193
+ end
194
+
195
+ File.open(file, 'w') {|f| f << data.to_yaml}
196
+
197
+ else
198
+ @error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
199
+ return false
200
+ end
201
+
202
+ return true
203
+ rescue Exception => e
204
+ @error_msg = "#{I18n.t('error.export.write', file: file)}\n#{e}"
205
+ return false
206
+ end
207
+
208
+ # Import to csv
209
+ # @args: file -> path to file import
210
+ # type -> udata type
211
+ # @rtrn: true if the import work
212
+ def import(file, type=:yaml)
213
+ case type
214
+ when :csv
215
+ CSV.foreach(file, {headers: true}) do |row|
216
+ item = Item.new(name: row['name'],
217
+ group: row['group'],
218
+ host: row['host'],
219
+ protocol: row['protocol'],
220
+ user: row['user'],
221
+ password: row['password'],
222
+ port: row['port'],
223
+ comment: row['comment'],
224
+ )
225
+
226
+ return false if item.empty?
227
+
228
+ @data.push(item)
229
+ end
230
+
231
+ when :yaml
232
+ YAML::load_file(file).each_value do |row|
233
+ item = Item.new(name: row['name'],
234
+ group: row['group'],
235
+ host: row['host'],
236
+ protocol: row['protocol'],
237
+ user: row['user'],
238
+ password: row['password'],
239
+ port: row['port'],
240
+ comment: row['comment'],
241
+ )
242
+
243
+ return false if item.empty?
244
+
245
+ @data.push(item)
246
+ end
247
+
248
+ else
249
+ @error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
250
+ return false
251
+ end
252
+
253
+ return true
254
+ rescue Exception => e
255
+ @error_msg = "#{I18n.t('error.import.read', file: file)}\n#{e}"
256
+ return false
257
+ end
258
+
259
+ # Return a preview import
260
+ # @args: file -> path to file import
261
+ # @rtrn: a hash with the items to import, if there is an error return false
262
+ def import_preview(file, type=:yaml)
263
+ data = []
264
+
265
+ case type
266
+ when :csv
267
+ CSV.foreach(file, {headers: true}) do |row|
268
+ item = Item.new(name: row['name'],
269
+ group: row['group'],
270
+ host: row['host'],
271
+ protocol: row['protocol'],
272
+ user: row['user'],
273
+ password: row['password'],
274
+ port: row['port'],
275
+ comment: row['comment'],
276
+ )
277
+
278
+ return false if item.empty?
279
+
280
+ data.push(item)
281
+ end
282
+
283
+ when :yaml
284
+ YAML::load_file(file).each_value do |row|
285
+ item = Item.new(name: row['name'],
286
+ group: row['group'],
287
+ host: row['host'],
288
+ protocol: row['protocol'],
289
+ user: row['user'],
290
+ password: row['password'],
291
+ port: row['port'],
292
+ comment: row['comment'],
293
+ )
294
+
295
+ return false if item.empty?
296
+
297
+ data.push(item)
298
+ end
299
+
300
+ else
301
+ @error_msg = "#{I18n.t('error.export.unknown_type', type: type)}"
302
+ return false
303
+ end
304
+
305
+ return data
306
+ rescue Exception => e
307
+ @error_msg = "#{I18n.t('error.import.read', file: file)}\n#{e}"
308
+ return false
309
+ end
310
+
311
+ # Generate a random password
312
+ # @args: length -> the length password
313
+ # @rtrn: a random string
314
+ def self.password(length=8)
315
+ if length.to_i <= 0
316
+ length = 8
317
+ else
318
+ length = length.to_i
319
+ end
320
+
321
+ result = ''
322
+ while length > 62 do
323
+ result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(62).join
324
+ length -= 62
325
+ end
326
+ result << ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
327
+
328
+ return result
329
+ end
330
+
331
+ end
332
+ end