mpw 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/CHANGELOG +13 -0
- data/Gemfile +10 -0
- data/LICENSE +339 -0
- data/README.md +14 -0
- data/VERSION +1 -0
- data/bin/mpw +165 -0
- data/bin/mpw-server +78 -0
- data/bin/mpw-ssh +89 -0
- data/i18n/cli/en.yml +149 -0
- data/i18n/cli/fr.yml +149 -0
- data/i18n/server/en.yml +26 -0
- data/i18n/server/fr.yml +26 -0
- data/lib/mpw/config.rb +231 -0
- data/lib/mpw/item.rb +109 -0
- data/lib/mpw/mpw.rb +332 -0
- data/lib/mpw/server.rb +343 -0
- data/lib/mpw/sync/ftp.rb +81 -0
- data/lib/mpw/sync/mpw.rb +124 -0
- data/lib/mpw/sync/ssh.rb +80 -0
- data/lib/mpw/sync.rb +138 -0
- data/lib/mpw/ui/cli.rb +324 -0
- data/lib/mpw/ui/clissh.rb +42 -0
- data/mpw.gemspec +19 -0
- data/test/files/fixtures.yml +32 -0
- data/test/files/test_import.csv +3 -0
- data/test/files/test_import.yml +23 -0
- data/test/test_item.rb +218 -0
- data/test/test_mpw.rb +191 -0
- data/test/tests.rb +4 -0
- metadata +82 -0
data/lib/mpw/server.rb
ADDED
@@ -0,0 +1,343 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module MPW
|
4
|
+
|
5
|
+
require 'socket'
|
6
|
+
require 'json'
|
7
|
+
require 'highline/import'
|
8
|
+
require 'digest'
|
9
|
+
require 'logger'
|
10
|
+
|
11
|
+
|
12
|
+
class Server
|
13
|
+
|
14
|
+
attr_accessor :error_msg
|
15
|
+
|
16
|
+
# Constructor
|
17
|
+
def initialize
|
18
|
+
YAML::ENGINE.yamler='syck'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Start the server
|
22
|
+
def start
|
23
|
+
server = TCPServer.open(@host, @port)
|
24
|
+
@log.info("The server is started on #{@host}:#{@port}")
|
25
|
+
|
26
|
+
loop do
|
27
|
+
Thread.start(server.accept) do |client|
|
28
|
+
@log.info("#{client.peeraddr[3]} is connected")
|
29
|
+
|
30
|
+
while true do
|
31
|
+
msg = get_client_msg(client)
|
32
|
+
|
33
|
+
next if not msg
|
34
|
+
|
35
|
+
if msg['gpg_key'].nil? or msg['gpg_key'].empty? or msg['password'].nil? or msg['password'].empty?
|
36
|
+
@log.warning("#{client.peeraddr[3]} is disconnected because no password or no gpg_key")
|
37
|
+
close_connection(client)
|
38
|
+
next
|
39
|
+
end
|
40
|
+
|
41
|
+
case msg['action']
|
42
|
+
when 'get'
|
43
|
+
@log.debug("#{client.peeraddr[3]} GET gpg_key=#{msg['gpg_key']} suffix=#{msg['suffix']}")
|
44
|
+
client.puts get_file(msg)
|
45
|
+
when 'update'
|
46
|
+
@log.debug("#{client.peeraddr[3]} UPDATE gpg_key=#{msg['gpg_key']} suffix=#{msg['suffix']}")
|
47
|
+
client.puts update_file(msg)
|
48
|
+
when 'delete'
|
49
|
+
@log.debug("#{client.peeraddr[3]} DELETE gpg_key=#{msg['gpg_key']} suffix=#{msg['suffix']}")
|
50
|
+
client.puts delete_file(msg)
|
51
|
+
else
|
52
|
+
@log.warning("#{client.peeraddr[3]} is disconnected because unkwnow command")
|
53
|
+
send_msg = {action: 'unknown',
|
54
|
+
gpg_key: msg['gpg_key'],
|
55
|
+
error: 'server.error.client.unknown'
|
56
|
+
}
|
57
|
+
client.puts send_msg
|
58
|
+
close_connection(client)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
rescue Exception => e
|
65
|
+
puts "Impossible to start the server: #{e}"
|
66
|
+
@log.error("Impossible to start the server: #{e}")
|
67
|
+
exit 2
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get a gpg file
|
71
|
+
# @args: msg -> message puts by the client
|
72
|
+
# @rtrn: json message
|
73
|
+
def get_file(msg)
|
74
|
+
gpg_key = msg['gpg_key'].sub('@', '_')
|
75
|
+
|
76
|
+
if msg['suffix'].nil? or msg['suffix'].empty?
|
77
|
+
file_gpg = "#{@data_dir}/#{gpg_key}.yml"
|
78
|
+
else
|
79
|
+
file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
|
80
|
+
end
|
81
|
+
|
82
|
+
if File.exist?(file_gpg)
|
83
|
+
gpg_data = YAML::load_file(file_gpg)
|
84
|
+
salt = gpg_data['gpg']['salt']
|
85
|
+
hash = gpg_data['gpg']['hash']
|
86
|
+
data = gpg_data['gpg']['data']
|
87
|
+
|
88
|
+
if is_authorized?(msg['password'], salt, hash)
|
89
|
+
send_msg = {action: 'get',
|
90
|
+
gpg_key: msg['gpg_key'],
|
91
|
+
data: data,
|
92
|
+
error: nil
|
93
|
+
}
|
94
|
+
else
|
95
|
+
send_msg = {action: 'get',
|
96
|
+
gpg_key: msg['gpg_key'],
|
97
|
+
error: 'server.error.client.no_authorized'
|
98
|
+
}
|
99
|
+
end
|
100
|
+
else
|
101
|
+
send_msg = {action: 'get',
|
102
|
+
gpg_key: msg['gpg_key'],
|
103
|
+
data: '',
|
104
|
+
error: nil
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
return send_msg.to_json
|
109
|
+
end
|
110
|
+
|
111
|
+
# Update a file
|
112
|
+
# @args: msg -> message puts by the client
|
113
|
+
# @rtrn: json message
|
114
|
+
def update_file(msg)
|
115
|
+
gpg_key = msg['gpg_key'].sub('@', '_')
|
116
|
+
data = msg['data']
|
117
|
+
|
118
|
+
if data.nil? or data.empty?
|
119
|
+
send_msg = {action: 'update',
|
120
|
+
gpg_key: msg['gpg_key'],
|
121
|
+
error: 'server.error.client.no_data'
|
122
|
+
}
|
123
|
+
|
124
|
+
return send_msg.to_json
|
125
|
+
end
|
126
|
+
|
127
|
+
if msg['suffix'].nil? or msg['suffix'].empty?
|
128
|
+
file_gpg = "#{@data_dir}/#{gpg_key}.yml"
|
129
|
+
else
|
130
|
+
file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
|
131
|
+
end
|
132
|
+
|
133
|
+
if File.exist?(file_gpg)
|
134
|
+
gpg_data = YAML::load_file(file_gpg)
|
135
|
+
salt = gpg_data['gpg']['salt']
|
136
|
+
hash = gpg_data['gpg']['hash']
|
137
|
+
|
138
|
+
else
|
139
|
+
salt = generate_salt
|
140
|
+
hash = Digest::SHA256.hexdigest(salt + msg['password'])
|
141
|
+
end
|
142
|
+
|
143
|
+
if is_authorized?(msg['password'], salt, hash)
|
144
|
+
begin
|
145
|
+
config = {'gpg' => {'salt' => salt,
|
146
|
+
'hash' => hash,
|
147
|
+
'data' => data
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
File.open(file_gpg, 'w+') do |file|
|
152
|
+
file << config.to_yaml
|
153
|
+
end
|
154
|
+
|
155
|
+
send_msg = {action: 'update',
|
156
|
+
gpg_key: msg['gpg_key'],
|
157
|
+
error: nil
|
158
|
+
}
|
159
|
+
rescue Exception => e
|
160
|
+
send_msg = {action: 'update',
|
161
|
+
gpg_key: msg['gpg_key'],
|
162
|
+
error: 'server.error.client.unknown'
|
163
|
+
}
|
164
|
+
end
|
165
|
+
else
|
166
|
+
send_msg = {action: 'update',
|
167
|
+
gpg_key: msg['gpg_key'],
|
168
|
+
error: 'server.error.client.no_authorized'
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
return send_msg.to_json
|
173
|
+
end
|
174
|
+
|
175
|
+
# Remove a gpg file
|
176
|
+
# @args: msg -> message puts by the client
|
177
|
+
# @rtrn: json message
|
178
|
+
def delete_file(msg)
|
179
|
+
gpg_key = msg['gpg_key'].sub('@', '_')
|
180
|
+
|
181
|
+
if msg['suffix'].nil? or msg['suffix'].empty?
|
182
|
+
file_gpg = "#{@data_dir}/#{gpg_key}.yml"
|
183
|
+
else
|
184
|
+
file_gpg = "#{@data_dir}/#{gpg_key}-#{msg['suffix']}.yml"
|
185
|
+
end
|
186
|
+
|
187
|
+
if not File.exist?(file_gpg)
|
188
|
+
send_msg = {:action => 'delete',
|
189
|
+
:gpg_key => msg['gpg_key'],
|
190
|
+
:error => nil
|
191
|
+
}
|
192
|
+
|
193
|
+
return send_msg.to_json
|
194
|
+
end
|
195
|
+
|
196
|
+
gpg_data = YAML::load_file(file_gpg)
|
197
|
+
salt = gpg_data['gpg']['salt']
|
198
|
+
hash = gpg_data['gpg']['hash']
|
199
|
+
|
200
|
+
if is_authorized?(msg['password'], salt, hash)
|
201
|
+
begin
|
202
|
+
File.unlink(file_gpg)
|
203
|
+
|
204
|
+
send_msg = {action: 'delete',
|
205
|
+
gpg_key: msg['gpg_key'],
|
206
|
+
error: nil
|
207
|
+
}
|
208
|
+
rescue Exception => e
|
209
|
+
send_msg = {action: 'delete',
|
210
|
+
gpg_key: msg['gpg_key'],
|
211
|
+
error: 'server.error.client.unknown'
|
212
|
+
}
|
213
|
+
end
|
214
|
+
else
|
215
|
+
send_msg = {action: 'delete',
|
216
|
+
gpg_key: msg['gpg_key'],
|
217
|
+
error: 'server.error.client.no_authorized'
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
return send_msg.to_json
|
222
|
+
end
|
223
|
+
|
224
|
+
# Check is the hash equal the password with the salt
|
225
|
+
# @args: password -> the user password
|
226
|
+
# salt -> the salt
|
227
|
+
# hash -> the hash of the password with the salt
|
228
|
+
# @rtrn: true is is good, else false
|
229
|
+
def is_authorized?(password, salt, hash)
|
230
|
+
if hash == Digest::SHA256.hexdigest(salt + password)
|
231
|
+
return true
|
232
|
+
else
|
233
|
+
return false
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Get message to client
|
238
|
+
# @args: client -> client connection
|
239
|
+
# @rtrn: array of the json string, or false if isn't json message
|
240
|
+
def get_client_msg(client)
|
241
|
+
msg = client.gets
|
242
|
+
return JSON.parse(msg)
|
243
|
+
rescue
|
244
|
+
closeConnection(client)
|
245
|
+
return false
|
246
|
+
end
|
247
|
+
|
248
|
+
# Close the client connection
|
249
|
+
# @args: client -> client connection
|
250
|
+
def close_connection(client)
|
251
|
+
client.puts "Closing the connection. Bye!"
|
252
|
+
client.close
|
253
|
+
end
|
254
|
+
|
255
|
+
# Check the config file
|
256
|
+
# @args: file_config -> the configuration file
|
257
|
+
# @rtrn: true if the config file is correct
|
258
|
+
def checkconfig(file_config)
|
259
|
+
config = YAML::load_file(file_config)
|
260
|
+
@host = config['config']['host']
|
261
|
+
@port = config['config']['port'].to_i
|
262
|
+
@data_dir = config['config']['data_dir']
|
263
|
+
@log_file = config['config']['log_file']
|
264
|
+
@timeout = config['config']['timeout'].to_i
|
265
|
+
|
266
|
+
if @host.empty? or @port <= 0 or @data_dir.empty?
|
267
|
+
puts I18n.t('checkconfig.fail')
|
268
|
+
puts I18n.t('checkconfig.empty')
|
269
|
+
return false
|
270
|
+
end
|
271
|
+
|
272
|
+
if not Dir.exist?(@data_dir)
|
273
|
+
puts I18n.t('checkconfig.fail')
|
274
|
+
puts I18n.t('checkconfig.datadir')
|
275
|
+
return false
|
276
|
+
end
|
277
|
+
|
278
|
+
if @log_file.nil? or @log_file.empty?
|
279
|
+
puts I18n.t('checkconfig.fail')
|
280
|
+
puts I18n.t('checkconfig.log_file_empty')
|
281
|
+
return false
|
282
|
+
else
|
283
|
+
begin
|
284
|
+
@log = Logger.new(@log_file)
|
285
|
+
rescue
|
286
|
+
puts I18n.t('checkconfig.fail')
|
287
|
+
puts I18n.t('checkconfig.log_file_create')
|
288
|
+
return false
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
return true
|
293
|
+
rescue Exception => e
|
294
|
+
puts "#{I18n.t('checkconfig.fail')}\n#{e}"
|
295
|
+
return false
|
296
|
+
end
|
297
|
+
|
298
|
+
# Create a new config file
|
299
|
+
# @args: file_config -> the configuration file
|
300
|
+
# @rtrn: true if le config file is create
|
301
|
+
def setup(file_config)
|
302
|
+
puts I18n.t('form.setup.title')
|
303
|
+
puts '--------------------'
|
304
|
+
host = ask(I18n.t('form.setup.host')).to_s
|
305
|
+
port = ask(I18n.t('form.setup.port')).to_s
|
306
|
+
data_dir = ask(I18n.t('form.setup.data_dir')).to_s
|
307
|
+
log_file = ask(I18n.t('form.setup.log_file')).to_s
|
308
|
+
timeout = ask(I18n.t('form.setup.timeout')).to_s
|
309
|
+
|
310
|
+
config = {'config' => {'host' => host,
|
311
|
+
'port' => port,
|
312
|
+
'data_dir' => data_dir,
|
313
|
+
'log_file' => log_file,
|
314
|
+
'timeout' => timeout
|
315
|
+
}
|
316
|
+
}
|
317
|
+
|
318
|
+
File.open(file_config, 'w') do |file|
|
319
|
+
file << config.to_yaml
|
320
|
+
end
|
321
|
+
|
322
|
+
return true
|
323
|
+
rescue Exception => e
|
324
|
+
puts "#{I18n.t('form.setup.not_valid')}\n#{e}"
|
325
|
+
return false
|
326
|
+
end
|
327
|
+
|
328
|
+
# Generate a random salt
|
329
|
+
# @args: length -> the length salt
|
330
|
+
# @rtrn: a random string
|
331
|
+
def generate_salt(length=4)
|
332
|
+
if length.to_i <= 0 or length.to_i > 16
|
333
|
+
length = 4
|
334
|
+
else
|
335
|
+
length = length.to_i
|
336
|
+
end
|
337
|
+
|
338
|
+
return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(length).join
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
end
|
data/lib/mpw/sync/ftp.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# author: nishiki
|
3
|
+
# mail: nishiki@yaegashi.fr
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'i18n'
|
7
|
+
require 'net/ftp'
|
8
|
+
|
9
|
+
module MPW
|
10
|
+
class FTP
|
11
|
+
|
12
|
+
attr_accessor :error_msg
|
13
|
+
attr_accessor :enable
|
14
|
+
|
15
|
+
# Constructor
|
16
|
+
# @args: host -> the server host
|
17
|
+
# port -> ther connection port
|
18
|
+
# gpg_key -> the gpg key
|
19
|
+
# password -> the remote password
|
20
|
+
# suffix -> the suffix file
|
21
|
+
def initialize(host, user, password, path, port=nil)
|
22
|
+
@error_msg = nil
|
23
|
+
@enable = false
|
24
|
+
|
25
|
+
@host = host
|
26
|
+
@user = user
|
27
|
+
@password = password
|
28
|
+
@path = path
|
29
|
+
@port = port.instance_of?(Integer) ? 21 : port
|
30
|
+
end
|
31
|
+
|
32
|
+
# Connect to server
|
33
|
+
# @rtrn: false if the connection fail
|
34
|
+
def connect
|
35
|
+
Net::FTP.open(@host) do |ftp|
|
36
|
+
ftp.login(@user, @password)
|
37
|
+
@enable = true
|
38
|
+
end
|
39
|
+
rescue Exception => e
|
40
|
+
@error_msg = "#{I18n.t('error.sync.connection')}\n#{e}"
|
41
|
+
@enable = false
|
42
|
+
else
|
43
|
+
return @enable
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get data on server
|
47
|
+
# @args: gpg_password -> the gpg password
|
48
|
+
# @rtrn: nil if nothing data or error
|
49
|
+
def get(file_tmp)
|
50
|
+
return false if not @enable
|
51
|
+
|
52
|
+
Net::FTP.open(@host) do |ftp|
|
53
|
+
ftp.login(@user, @password)
|
54
|
+
ftp.gettextfile(@path, file_tmp)
|
55
|
+
end
|
56
|
+
|
57
|
+
return true
|
58
|
+
rescue Exception => e
|
59
|
+
@error_msg = "#{I18n.t('error.sync.download')}\n#{e}"
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Update the remote data
|
64
|
+
# @args: data -> the data to send on server
|
65
|
+
# @rtrn: false if there is a problem
|
66
|
+
def update(file_gpg)
|
67
|
+
return true if not @enable
|
68
|
+
|
69
|
+
Net::FTP.open(@host) do |ftp|
|
70
|
+
ftp.login(@user, @password)
|
71
|
+
ftp.puttextfile(file_gpg, @path)
|
72
|
+
end
|
73
|
+
|
74
|
+
return true
|
75
|
+
rescue Exception => e
|
76
|
+
@error_msg = "#{I18n.t('error.sync.upload')}\n#{e}"
|
77
|
+
return false
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/mpw/sync/mpw.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# author: nishiki
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'i18n'
|
6
|
+
require 'socket'
|
7
|
+
require 'json'
|
8
|
+
require 'timeout'
|
9
|
+
|
10
|
+
module MPW
|
11
|
+
class SyncMPW
|
12
|
+
|
13
|
+
attr_accessor :error_msg
|
14
|
+
attr_accessor :enable
|
15
|
+
|
16
|
+
# Constructor
|
17
|
+
# @args: host -> the server host
|
18
|
+
# port -> ther connection port
|
19
|
+
# gpg_key -> the gpg key
|
20
|
+
# password -> the remote password
|
21
|
+
# suffix -> the suffix file
|
22
|
+
def initialize(host, user, password, suffix, port=nil)
|
23
|
+
@error_msg = nil
|
24
|
+
@enable = false
|
25
|
+
|
26
|
+
@host = host
|
27
|
+
@port = !port.instance_of?(Integer) ? 2201 : port
|
28
|
+
@gpg_key = user
|
29
|
+
@password = password
|
30
|
+
@suffix = suffix
|
31
|
+
end
|
32
|
+
|
33
|
+
# Connect to server
|
34
|
+
# @rtrn: false if the connection fail
|
35
|
+
def connect
|
36
|
+
Timeout.timeout(10) do
|
37
|
+
begin
|
38
|
+
TCPSocket.open(@host, @port) do
|
39
|
+
@enable = true
|
40
|
+
end
|
41
|
+
rescue Errno::ENETUNREACH
|
42
|
+
retry
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Timeout::Error
|
46
|
+
@error_msg = "#{I18n.t('error.timeout')}\n#{e}"
|
47
|
+
@enable = false
|
48
|
+
rescue Exception => e
|
49
|
+
@error_msg = "#{I18n.t('error.sync.connection')}\n#{e}"
|
50
|
+
@enable = false
|
51
|
+
else
|
52
|
+
return @enable
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get data on server
|
56
|
+
# @args: gpg_password -> the gpg password
|
57
|
+
# @rtrn: nil if nothing data or error
|
58
|
+
def get(file_tmp)
|
59
|
+
return false if not @enable
|
60
|
+
|
61
|
+
msg = nil
|
62
|
+
TCPSocket.open(@host, @port) do |socket|
|
63
|
+
send_msg = {action: 'get',
|
64
|
+
gpg_key: @gpg_key,
|
65
|
+
password: @password,
|
66
|
+
suffix: @suffix
|
67
|
+
}
|
68
|
+
|
69
|
+
socket.puts send_msg.to_json
|
70
|
+
msg = JSON.parse(socket.gets)
|
71
|
+
end
|
72
|
+
|
73
|
+
if not defined?(msg['error'])
|
74
|
+
@error_msg = I18n.t('error.sync.communication')
|
75
|
+
return false
|
76
|
+
elsif not msg['error'].nil?
|
77
|
+
@error_msg = I18n.t(msg['error'])
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
|
81
|
+
File.open(file_tmp, 'w') do |file|
|
82
|
+
file << msg['data']
|
83
|
+
end
|
84
|
+
|
85
|
+
return true
|
86
|
+
rescue Exception => e
|
87
|
+
@error_msg = "#{I18n.t('error.sync.download')}\n#{e}"
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
|
91
|
+
# Update the remote data
|
92
|
+
# @args: data -> the data to send on server
|
93
|
+
# @rtrn: false if there is a problem
|
94
|
+
def update(file_gpg)
|
95
|
+
return true if not @enable
|
96
|
+
|
97
|
+
data = File.open(file_gpg, 'r').read
|
98
|
+
|
99
|
+
msg = nil
|
100
|
+
TCPSocket.open(@host, @port) do |socket|
|
101
|
+
send_msg = {action: 'update',
|
102
|
+
gpg_key: @gpg_key,
|
103
|
+
password: @password,
|
104
|
+
suffix: @suffix,
|
105
|
+
data: data
|
106
|
+
}
|
107
|
+
|
108
|
+
socket.puts send_msg.to_json
|
109
|
+
msg = JSON.parse(socket.gets)
|
110
|
+
end
|
111
|
+
|
112
|
+
if not defined?(msg['error'])
|
113
|
+
@error_msg = I18n.t('error.sync.communication')
|
114
|
+
return false
|
115
|
+
elsif msg['error'].nil?
|
116
|
+
return true
|
117
|
+
else
|
118
|
+
@error_msg = I18n.t(msg['error'])
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
data/lib/mpw/sync/ssh.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# author: nishiki
|
3
|
+
# mail: nishiki@yaegashi.fr
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'i18n'
|
7
|
+
require 'net/ssh'
|
8
|
+
require 'net/sftp'
|
9
|
+
|
10
|
+
module MPW
|
11
|
+
class SyncSSH
|
12
|
+
|
13
|
+
attr_accessor :error_msg
|
14
|
+
attr_accessor :enable
|
15
|
+
|
16
|
+
# Constructor
|
17
|
+
# @args: host -> the server host
|
18
|
+
# port -> ther connection port
|
19
|
+
# gpg_key -> the gpg key
|
20
|
+
# password -> the remote password
|
21
|
+
def initialize(host, user, password, path, port=nil)
|
22
|
+
@error_msg = nil
|
23
|
+
@enable = false
|
24
|
+
|
25
|
+
@host = host
|
26
|
+
@user = user
|
27
|
+
@password = password
|
28
|
+
@path = path
|
29
|
+
@port = port.instance_of?(Integer) ? 22 : port
|
30
|
+
end
|
31
|
+
|
32
|
+
# Connect to server
|
33
|
+
# @rtrn: false if the connection fail
|
34
|
+
def connect
|
35
|
+
Net::SSH.start(@host, @user, password: @password, port: @port) do |ssh|
|
36
|
+
@enable = true
|
37
|
+
end
|
38
|
+
rescue Exception => e
|
39
|
+
@error_msg = "#{I18n.t('error.sync.connection')}\n#{e}"
|
40
|
+
@enable = false
|
41
|
+
else
|
42
|
+
return @enable
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get data on server
|
46
|
+
# @args: gpg_password -> the gpg password
|
47
|
+
# @rtrn: nil if nothing data or error
|
48
|
+
def get(file_tmp)
|
49
|
+
return false if not @enable
|
50
|
+
|
51
|
+
Net::SFTP.start(@host, @user, password: @password, port: @port) do |sftp|
|
52
|
+
sftp.lstat(@path) do |response|
|
53
|
+
sftp.download!(@path, file_tmp) if response.ok?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return true
|
58
|
+
rescue Exception => e
|
59
|
+
@error_msg = "#{I18n.t('error.sync.download')}\n#{e}"
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Update the remote data
|
64
|
+
# @args: file_gpg -> the data to send on server
|
65
|
+
# @rtrn: false if there is a problem
|
66
|
+
def update(file_gpg)
|
67
|
+
return true if not @enable
|
68
|
+
|
69
|
+
Net::SFTP.start(@host, @user, password: @password, port: @port) do |sftp|
|
70
|
+
sftp.upload!(file_gpg, @path)
|
71
|
+
end
|
72
|
+
|
73
|
+
return true
|
74
|
+
rescue Exception => e
|
75
|
+
@error_msg = "#{I18n.t('error.sync.upload')}\n#{e}"
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|