rcs-common 9.6.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.
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