rcs-common 9.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -0
- data/Rakefile +27 -0
- data/lib/rcs-common.rb +21 -0
- data/lib/rcs-common/binary.rb +64 -0
- data/lib/rcs-common/cgi.rb +7 -0
- data/lib/rcs-common/component.rb +87 -0
- data/lib/rcs-common/crypt.rb +71 -0
- data/lib/rcs-common/deploy.rb +96 -0
- data/lib/rcs-common/diagnosticable.rb +136 -0
- data/lib/rcs-common/evidence.rb +261 -0
- data/lib/rcs-common/evidence/addressbook.rb +173 -0
- data/lib/rcs-common/evidence/application.rb +59 -0
- data/lib/rcs-common/evidence/calendar.rb +62 -0
- data/lib/rcs-common/evidence/call.rb +185 -0
- data/lib/rcs-common/evidence/camera.rb +25 -0
- data/lib/rcs-common/evidence/chat.rb +272 -0
- data/lib/rcs-common/evidence/clibpoard.rb +58 -0
- data/lib/rcs-common/evidence/command.rb +50 -0
- data/lib/rcs-common/evidence/common.rb +78 -0
- data/lib/rcs-common/evidence/content/camera/001.jpg +0 -0
- data/lib/rcs-common/evidence/content/coin/wallet_bit.dat +0 -0
- data/lib/rcs-common/evidence/content/coin/wallet_lite.dat +0 -0
- data/lib/rcs-common/evidence/content/file/Einstein.docx +0 -0
- data/lib/rcs-common/evidence/content/file/arabic.docx +0 -0
- data/lib/rcs-common/evidence/content/mouse/001.jpg +0 -0
- data/lib/rcs-common/evidence/content/mouse/002.jpg +0 -0
- data/lib/rcs-common/evidence/content/mouse/003.jpg +0 -0
- data/lib/rcs-common/evidence/content/mouse/004.jpg +0 -0
- data/lib/rcs-common/evidence/content/print/001.jpg +0 -0
- data/lib/rcs-common/evidence/content/screenshot/001.jpg +0 -0
- data/lib/rcs-common/evidence/content/screenshot/002.jpg +0 -0
- data/lib/rcs-common/evidence/content/screenshot/003.jpg +0 -0
- data/lib/rcs-common/evidence/content/url/001.jpg +0 -0
- data/lib/rcs-common/evidence/content/url/002.jpg +0 -0
- data/lib/rcs-common/evidence/content/url/003.jpg +0 -0
- data/lib/rcs-common/evidence/device.rb +23 -0
- data/lib/rcs-common/evidence/download.rb +54 -0
- data/lib/rcs-common/evidence/exec.rb +0 -0
- data/lib/rcs-common/evidence/file.rb +129 -0
- data/lib/rcs-common/evidence/filesystem.rb +71 -0
- data/lib/rcs-common/evidence/info.rb +24 -0
- data/lib/rcs-common/evidence/keylog.rb +84 -0
- data/lib/rcs-common/evidence/mail.rb +237 -0
- data/lib/rcs-common/evidence/mic.rb +39 -0
- data/lib/rcs-common/evidence/mms.rb +36 -0
- data/lib/rcs-common/evidence/money.rb +676 -0
- data/lib/rcs-common/evidence/mouse.rb +62 -0
- data/lib/rcs-common/evidence/password.rb +60 -0
- data/lib/rcs-common/evidence/photo.rb +80 -0
- data/lib/rcs-common/evidence/position.rb +303 -0
- data/lib/rcs-common/evidence/print.rb +50 -0
- data/lib/rcs-common/evidence/screenshot.rb +53 -0
- data/lib/rcs-common/evidence/sms.rb +91 -0
- data/lib/rcs-common/evidence/url.rb +133 -0
- data/lib/rcs-common/fixnum.rb +48 -0
- data/lib/rcs-common/gridfs.rb +294 -0
- data/lib/rcs-common/heartbeat.rb +96 -0
- data/lib/rcs-common/keywords.rb +50 -0
- data/lib/rcs-common/mime.rb +65 -0
- data/lib/rcs-common/mongoid.rb +19 -0
- data/lib/rcs-common/pascalize.rb +62 -0
- data/lib/rcs-common/path_utils.rb +67 -0
- data/lib/rcs-common/resolver.rb +40 -0
- data/lib/rcs-common/rest.rb +17 -0
- data/lib/rcs-common/sanitize.rb +42 -0
- data/lib/rcs-common/serializer.rb +404 -0
- data/lib/rcs-common/signature.rb +141 -0
- data/lib/rcs-common/stats.rb +94 -0
- data/lib/rcs-common/symbolize.rb +10 -0
- data/lib/rcs-common/systemstatus.rb +136 -0
- data/lib/rcs-common/temporary.rb +13 -0
- data/lib/rcs-common/time.rb +24 -0
- data/lib/rcs-common/trace.rb +138 -0
- data/lib/rcs-common/trace.yaml +42 -0
- data/lib/rcs-common/updater/client.rb +354 -0
- data/lib/rcs-common/updater/dsl.rb +178 -0
- data/lib/rcs-common/updater/payload.rb +79 -0
- data/lib/rcs-common/updater/server.rb +126 -0
- data/lib/rcs-common/updater/shared_key.rb +55 -0
- data/lib/rcs-common/updater/tmp_dir.rb +13 -0
- data/lib/rcs-common/utf16le.rb +83 -0
- data/lib/rcs-common/version.rb +5 -0
- data/lib/rcs-common/winfirewall.rb +235 -0
- data/rcs-common.gemspec +64 -0
- data/spec/gridfs_spec.rb +637 -0
- data/spec/mongoid.yaml +6 -0
- data/spec/signature_spec.rb +105 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/updater_spec.rb +80 -0
- data/tasks/deploy.rake +21 -0
- data/tasks/protect.rake +90 -0
- data/test/helper.rb +17 -0
- data/test/test_binary.rb +107 -0
- data/test/test_cgi.rb +14 -0
- data/test/test_crypt.rb +125 -0
- data/test/test_evidence.rb +52 -0
- data/test/test_evidence_manager.rb +119 -0
- data/test/test_fixnum.rb +35 -0
- data/test/test_keywords.rb +137 -0
- data/test/test_mime.rb +49 -0
- data/test/test_pascalize.rb +100 -0
- data/test/test_path_utils.rb +24 -0
- data/test/test_rcs-common.rb +7 -0
- data/test/test_sanitize.rb +40 -0
- data/test/test_serialization.rb +20 -0
- data/test/test_stats.rb +90 -0
- data/test/test_symbolize.rb +20 -0
- data/test/test_systemstatus.rb +35 -0
- data/test/test_time.rb +56 -0
- data/test/test_trace.rb +25 -0
- data/test/test_utf16le.rb +71 -0
- data/test/test_winfirewall.rb +68 -0
- metadata +423 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f2b1ac857fbf21f06eb94d5a5e76cd178184b8ef
|
4
|
+
data.tar.gz: f6dc9cd9218eb48ac4a3a811edc3e7036266c0cb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: acbf20309baa1c68b561a28063863183a983fea9944775ded0881f88a38ce3e04c3b92cb42b906abd4abd36d2b2ab2a0de282e65853172debc04341b972f30c1
|
7
|
+
data.tar.gz: 300985b94d6b9144ba3993032f29e6d008cbb1e2e00164b54157964b1dd6daf1a75282c6806991f3bcaa3f6456f6c29c814f76896fcf36f255ffe9880dbdb884
|
data/.gitignore
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
Gemfile.lock
|
14
|
+
|
15
|
+
# jeweler generated
|
16
|
+
pkg
|
17
|
+
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
19
|
+
#
|
20
|
+
# * Create a file at ~/.gitignore
|
21
|
+
# * Include files you want ignored
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
23
|
+
#
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
26
|
+
#
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
28
|
+
#
|
29
|
+
# For MacOS:
|
30
|
+
#
|
31
|
+
.DS_Store
|
32
|
+
#
|
33
|
+
# For TextMate
|
34
|
+
#*.tmproj
|
35
|
+
#tmtags
|
36
|
+
#
|
37
|
+
# For emacs:
|
38
|
+
#*~
|
39
|
+
#\#*
|
40
|
+
#.\#*
|
41
|
+
#
|
42
|
+
# For vim:
|
43
|
+
#*.swp
|
44
|
+
|
45
|
+
# For RubyMine
|
46
|
+
.idea
|
47
|
+
|
48
|
+
# RVM gemset
|
49
|
+
.ruby-gemset
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Copyright (c) 2014 HT srl
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
Dir["./tasks/*.rake"].each do |path|
|
7
|
+
load(path)
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Run minitest"
|
11
|
+
Rake::TestTask.new(:test) do |test|
|
12
|
+
test.libs << 'lib' << 'test'
|
13
|
+
test.pattern = 'test/**/test_*.rb'
|
14
|
+
test.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run minitest + rspec"
|
18
|
+
task :default do
|
19
|
+
Rake::Task["test"].invoke
|
20
|
+
Rake::Task["spec"].invoke
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Run rspec"
|
24
|
+
RSpec::Core::RakeTask.new(:spec)
|
25
|
+
|
26
|
+
# Disable the release task (release the gem to rubygems)
|
27
|
+
Rake::Task["release"].clear
|
data/lib/rcs-common.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# helper modules
|
2
|
+
require 'rcs-common/time'
|
3
|
+
require 'rcs-common/utf16le'
|
4
|
+
|
5
|
+
require "rcs-common/version"
|
6
|
+
|
7
|
+
# gem modules
|
8
|
+
require 'rcs-common/crypt'
|
9
|
+
require 'rcs-common/pascalize'
|
10
|
+
require 'rcs-common/keywords'
|
11
|
+
require 'rcs-common/sanitize'
|
12
|
+
require 'rcs-common/trace'
|
13
|
+
require 'rcs-common/mime'
|
14
|
+
require 'rcs-common/systemstatus'
|
15
|
+
require 'rcs-common/fixnum'
|
16
|
+
require 'rcs-common/symbolize'
|
17
|
+
require 'rcs-common/utf16le'
|
18
|
+
require 'rcs-common/cgi'
|
19
|
+
require 'rcs-common/binary'
|
20
|
+
require 'rcs-common/stats'
|
21
|
+
require 'rcs-common/gridfs'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
# add a method to String to perform binary substitution
|
3
|
+
# without the hassles of regexp
|
4
|
+
|
5
|
+
class MatchNotFound < StandardError
|
6
|
+
def initialize
|
7
|
+
super "matching string not found"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class OutOfBounds < StandardError
|
12
|
+
def initialize
|
13
|
+
super "offset is out of bound"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class OutOfBoundsString < StandardError
|
18
|
+
def initialize
|
19
|
+
super "string too long, out of bound"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class String
|
24
|
+
def binary_patch(match, replace)
|
25
|
+
raise MatchNotFound unless self[match]
|
26
|
+
# use the block form to avoid the regexp in the replace string
|
27
|
+
self.gsub!(match.force_encoding('ASCII-8BIT')) do |param|
|
28
|
+
replace.force_encoding('ASCII-8BIT')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def binary_patch_at_offset(offset, replace)
|
33
|
+
io = StringIO.new(self)
|
34
|
+
|
35
|
+
# check for boundaries
|
36
|
+
raise OutOfBounds if offset < 0
|
37
|
+
raise OutOfBounds if offset > io.size
|
38
|
+
raise OutOfBoundsString if offset + replace.bytesize > io.size
|
39
|
+
|
40
|
+
io.pos = offset
|
41
|
+
io.write replace
|
42
|
+
io.close
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def binary_add_at_offset(offset, value)
|
47
|
+
io = StringIO.new(self)
|
48
|
+
|
49
|
+
# check for boundaries
|
50
|
+
raise OutOfBounds if offset < 0
|
51
|
+
raise OutOfBounds if offset > io.size
|
52
|
+
|
53
|
+
io.pos = offset
|
54
|
+
current = io.read(4).unpack('I').first
|
55
|
+
current += value
|
56
|
+
current = [current].pack('I')
|
57
|
+
|
58
|
+
io.pos = offset
|
59
|
+
io.write current
|
60
|
+
io.close
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rcs-common/trace'
|
2
|
+
|
3
|
+
module RCS
|
4
|
+
module Component
|
5
|
+
def self.included(base)
|
6
|
+
base.__send__(:include, RCS::Tracer)
|
7
|
+
base.__send__(:extend, RCS::Tracer)
|
8
|
+
|
9
|
+
base.__send__(:extend, ClassMethods)
|
10
|
+
|
11
|
+
base.__send__(:define_singleton_method, :component) do |value, name: nil|
|
12
|
+
@_component = value.to_sym
|
13
|
+
@_component_name = name || "RCS #{value.to_s.capitalize}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def component
|
18
|
+
self.class.instance_variable_get('@_component')
|
19
|
+
end
|
20
|
+
|
21
|
+
def component_name
|
22
|
+
self.class.instance_variable_get('@_component_name')
|
23
|
+
end
|
24
|
+
|
25
|
+
def full_component_version
|
26
|
+
File.read(Dir.pwd + '/config/VERSION').strip
|
27
|
+
end
|
28
|
+
|
29
|
+
def component_version
|
30
|
+
$version || full_component_version.split('-').first
|
31
|
+
end
|
32
|
+
|
33
|
+
def show_startup_message
|
34
|
+
build = File.read(Dir.pwd + '/config/VERSION_BUILD')
|
35
|
+
trace :fatal, "Starting the #{component_name} #{full_component_version} (#{build})..."
|
36
|
+
end
|
37
|
+
|
38
|
+
def database
|
39
|
+
@_database ||= begin
|
40
|
+
db_class = RCS.const_get('Collector::DB') rescue RCS.const_get('DB::DB')
|
41
|
+
db_class.instance
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def establish_database_connection(wait_until_connected: false)
|
46
|
+
loop do
|
47
|
+
connected = database.respond_to?(:connect!) ? database.connect!(component) : database.connect
|
48
|
+
|
49
|
+
if connected
|
50
|
+
trace :info, "Database connection succeeded"
|
51
|
+
break
|
52
|
+
end
|
53
|
+
|
54
|
+
if wait_until_connected
|
55
|
+
trace :warn, "Database connection failed, retry..."
|
56
|
+
sleep 1
|
57
|
+
else
|
58
|
+
trace :error, "Database connection failed"
|
59
|
+
break
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def run_with_rescue
|
65
|
+
$version = component_version
|
66
|
+
trace_setup
|
67
|
+
show_startup_message
|
68
|
+
yield
|
69
|
+
return 0
|
70
|
+
rescue Interrupt
|
71
|
+
# call the kill handler if defined
|
72
|
+
kill if self.respond_to? :kill
|
73
|
+
trace :info, "User asked to exit. Bye bye!"
|
74
|
+
exit(0)
|
75
|
+
rescue Exception => e
|
76
|
+
trace :fatal, "FAILURE: " << e.message
|
77
|
+
trace :fatal, "EXCEPTION: [#{e.class}] " << e.backtrace.join("\n")
|
78
|
+
exit(1)
|
79
|
+
end
|
80
|
+
|
81
|
+
module ClassMethods
|
82
|
+
def run!(*argv)
|
83
|
+
return new.run(argv)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#
|
2
|
+
# The encryption module.
|
3
|
+
# by default we use the PKCS5 padding
|
4
|
+
# force the third parameter to change the padding
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'openssl'
|
8
|
+
require 'digest/sha1'
|
9
|
+
|
10
|
+
module RCS
|
11
|
+
|
12
|
+
module Crypt
|
13
|
+
PAD_NOPAD = 0
|
14
|
+
PAD_PKCS5 = 1
|
15
|
+
SHA1_DIGEST_LENGTH = 20
|
16
|
+
|
17
|
+
def aes_encrypt(clear_text, key, padding=PAD_PKCS5)
|
18
|
+
cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
|
19
|
+
cipher.encrypt
|
20
|
+
cipher.padding = padding
|
21
|
+
cipher.key = key
|
22
|
+
cipher.iv = "\x00" * cipher.iv_len
|
23
|
+
edata = cipher.update(clear_text)
|
24
|
+
edata << cipher.final
|
25
|
+
return edata
|
26
|
+
end
|
27
|
+
|
28
|
+
def aes_decrypt(enc_text, key, padding=PAD_PKCS5)
|
29
|
+
decipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
|
30
|
+
decipher.decrypt
|
31
|
+
decipher.padding = padding
|
32
|
+
decipher.key = key
|
33
|
+
decipher.iv = "\x00" * decipher.iv_len
|
34
|
+
data = decipher.update(enc_text)
|
35
|
+
data << decipher.final
|
36
|
+
return data
|
37
|
+
end
|
38
|
+
|
39
|
+
def aes_encrypt_integrity(clear_text, key, padding=PAD_PKCS5)
|
40
|
+
# add the integrity check at the end of the message
|
41
|
+
clear_text += Digest::SHA1.digest(clear_text)
|
42
|
+
return aes_encrypt(clear_text, key, padding)
|
43
|
+
end
|
44
|
+
|
45
|
+
def aes_decrypt_integrity(enc_text, key, padding=PAD_PKCS5)
|
46
|
+
text = aes_decrypt(enc_text, key, padding)
|
47
|
+
# check the integrity at the end of the message
|
48
|
+
check = text.slice!(text.length - SHA1_DIGEST_LENGTH, text.length)
|
49
|
+
raise "Invalid sha1 check" unless check == Digest::SHA1.digest(text)
|
50
|
+
return text
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end #namespace
|
55
|
+
|
56
|
+
if __FILE__ == $0
|
57
|
+
require 'securerandom'
|
58
|
+
include RCS::Crypt
|
59
|
+
|
60
|
+
clear = SecureRandom.random_bytes(16)
|
61
|
+
key = Digest::MD5.digest "4yeN5zu0+il3Jtcb5a1sBcAdjYFcsD9z"
|
62
|
+
|
63
|
+
puts "DATA: " + clear.unpack('H*').to_s
|
64
|
+
enc = aes_encrypt(clear, key)
|
65
|
+
|
66
|
+
puts "ENC: " + enc.unpack('H*').to_s
|
67
|
+
dec = aes_decrypt(enc, key)
|
68
|
+
|
69
|
+
puts "DEC: " + dec.unpack('H*').to_s
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module RCS
|
2
|
+
class Deploy
|
3
|
+
attr_reader :me, :target
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
@target = Target.new(params)
|
7
|
+
@me = Me.new
|
8
|
+
end
|
9
|
+
|
10
|
+
class Me
|
11
|
+
attr_reader :path
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@path ||= File.expand_path(Dir.pwd)
|
15
|
+
|
16
|
+
raise "Missing rakefile" unless File.exists?("#{@path}/Rakefile")
|
17
|
+
raise "Not in a git repo" unless Dir.exists?("#{@path}/.git")
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(cmd, opts = {})
|
21
|
+
puts "executing: #{cmd}"
|
22
|
+
opts[:trap] ? `#{cmd}` : Kernel.system(cmd)
|
23
|
+
end
|
24
|
+
|
25
|
+
def pending_changes?
|
26
|
+
run("cd \"#{path}\" && git status", trap: true) !~ /nothing to commit, working directory clean/
|
27
|
+
end
|
28
|
+
|
29
|
+
def ask(question, yes_no: true, choices: %w[y n])
|
30
|
+
print("#{question} (#{choices.join(', ')}): ")
|
31
|
+
|
32
|
+
begin
|
33
|
+
answer = STDIN.readline.strip.downcase
|
34
|
+
yes_no ? (answer == 'y' or answer == 'yes') : answer
|
35
|
+
rescue Interrupt
|
36
|
+
puts "\nBye"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Target
|
43
|
+
attr_reader :user, :address
|
44
|
+
|
45
|
+
def initialize(params)
|
46
|
+
@user = params[:user]
|
47
|
+
@address = params[:address]
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_slash(path)
|
51
|
+
path.end_with?('/') ? "#{path}" : "#{path}/"
|
52
|
+
end
|
53
|
+
|
54
|
+
def transfer(src, remote_folder, opts = {})
|
55
|
+
dst = add_slash(remote_folder)
|
56
|
+
|
57
|
+
run_without_ssh("rsync -tcv #{src} #{user}@#{address}:\"#{dst}\"", opts)
|
58
|
+
end
|
59
|
+
|
60
|
+
def mirror!(local_folder, remote_folder, opts = {})
|
61
|
+
src = add_slash(local_folder)
|
62
|
+
dst = add_slash(remote_folder)
|
63
|
+
|
64
|
+
run_without_ssh("rsync --delete -vazc \"#{src}\" #{user}@#{address}:\"#{dst}\"", opts)
|
65
|
+
end
|
66
|
+
|
67
|
+
def mirror(local_folder, remote_folder, opts = {})
|
68
|
+
opts[:trap] = true
|
69
|
+
result = mirror!(local_folder, remote_folder, opts)
|
70
|
+
changes = result.split("\n")[1..-3].reject { |x| x.empty? }
|
71
|
+
changed = changes.size > 0 && changes != ["./"]
|
72
|
+
|
73
|
+
if opts[:changes]
|
74
|
+
changed ? result : nil
|
75
|
+
else
|
76
|
+
changed
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def restart_service(name)
|
81
|
+
run_with_ssh("net stop \"#{name}\"; net start \"#{name}\"")
|
82
|
+
end
|
83
|
+
|
84
|
+
def run_with_ssh(command, opts = {})
|
85
|
+
run_without_ssh("ssh #{user}@#{address} \""+ command.gsub('"', '\"') +"\"", opts)
|
86
|
+
end
|
87
|
+
|
88
|
+
alias :run :run_with_ssh
|
89
|
+
|
90
|
+
def run_without_ssh(cmd, opts = {})
|
91
|
+
puts "executing: #{cmd}"
|
92
|
+
opts[:trap] ? `#{cmd}` : Kernel.system(cmd)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|