test_server 0.4.1 → 0.5.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -3
  3. data/Gemfile +13 -5
  4. data/README.md +16 -0
  5. data/Rakefile +17 -3
  6. data/app/assets/javascripts/test_server/file_uploader.js.coffee +3 -0
  7. data/app/assets/stylesheets/application.scss +31 -0
  8. data/app/assets/stylesheets/test_server/file_uploader.css.scss +3 -0
  9. data/app/controllers/test_server/file_uploader_controller.rb +42 -0
  10. data/app/helpers/test_server/file_uploader_helper.rb +2 -0
  11. data/app/models/test_server/file_upload.rb +41 -0
  12. data/app/views/layouts/application.html.haml +10 -0
  13. data/app/views/test_server/dashboard/show.html.haml +1 -0
  14. data/app/views/test_server/file_uploader/_form.html.haml +27 -0
  15. data/app/views/test_server/file_uploader/_overview.html.haml +1 -0
  16. data/app/views/test_server/file_uploader/index.html.haml +1 -0
  17. data/app/views/test_server/file_uploader/result.html.haml +40 -0
  18. data/app/views/test_server/file_uploader/upload.html.haml +1 -0
  19. data/config/routes.rb +8 -2
  20. data/lib/test_server/checksum.rb +21 -0
  21. data/lib/test_server/checksum_calculator.rb +27 -0
  22. data/lib/test_server/command_runner.rb +58 -0
  23. data/lib/test_server/exceptions.rb +3 -0
  24. data/lib/test_server/file_size.rb +14 -0
  25. data/lib/test_server/filetype_detector.rb +21 -0
  26. data/lib/test_server/locales/en.yml +28 -1
  27. data/lib/test_server/main.rb +6 -1
  28. data/lib/test_server/md5_calculator.rb +17 -0
  29. data/lib/test_server/permitted_params.rb +25 -7
  30. data/lib/test_server/sha256_calculator.rb +17 -0
  31. data/lib/test_server/uploaded_file.rb +58 -0
  32. data/lib/test_server/version.rb +1 -1
  33. data/lib/test_server/virus_detector.rb +43 -0
  34. data/lib/test_server.rb +15 -0
  35. data/public/assets/{manifest-7c069da388f8a976fadfaab958b9feb7.json → manifest-1a3c45fcd482cca628c8cdc72631eb98.json} +0 -0
  36. data/spec/controllers/test_server/file_uploader_controller_spec.rb +26 -0
  37. data/spec/encoder_spec.rb +3 -3
  38. data/spec/features/fetch_data_via_javascript_spec.rb +18 -18
  39. data/spec/filetype_detector_spec.rb +31 -0
  40. data/spec/fixtures/file_uploader/file.bin +0 -0
  41. data/spec/permitted_params_spec.rb +1 -1
  42. data/spec/sha256_calculator_spec.rb +36 -0
  43. data/spec/spec_helper.rb +2 -0
  44. data/spec/support/commands.rb +15 -0
  45. data/spec/support/debugging.rb +6 -1
  46. data/spec/support/eicar.rb +15 -0
  47. data/spec/support/fixtures.rb +16 -0
  48. data/spec/support/rails.rb +2 -0
  49. data/spec/uploaded_file_spec.rb +167 -0
  50. data/spec/views/errors/not_found.html.haml_spec.rb +1 -1
  51. data/spec/views/test_server/file_uploader/index.html.haml_spec.rb +32 -0
  52. data/spec/views/test_server/file_uploader/result.html.haml_spec.rb +58 -0
  53. data/spec/views/test_server/file_uploader/upload.html.haml_spec.rb +12 -0
  54. data/spec/views/test_server/reflector/client_ip_address.html.haml_spec.rb +1 -1
  55. data/spec/virus_detector_spec.rb +45 -0
  56. data/test_server.gemspec +2 -3
  57. metadata +48 -19
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class ChecksumCalculator
4
+ private
5
+
6
+ attr_reader :engine
7
+
8
+ public
9
+
10
+ def use(file)
11
+ file.checksum = compute_checksum(file)
12
+ rescue StandardError => err
13
+ Rails.logger.error "#{err.class}: #{err.message}"
14
+
15
+ checksum = OpenStruct.new
16
+ checksum.value = "An error occured while determine checksum for \"#{file.name}\"."
17
+
18
+ file.checksum = checksum
19
+ end
20
+
21
+ private
22
+
23
+ def compute_checksum(file)
24
+ raise MethodNotImplemented, JSON.dump(method: :compute_checksum)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ require 'timeout'
3
+ require 'ostruct'
4
+
5
+ module TestServer
6
+ class CommandRunner
7
+
8
+ private
9
+
10
+ attr_reader :timeout
11
+
12
+ public
13
+
14
+ def initialize(timeout:)
15
+ @timeout = timeout
16
+ end
17
+
18
+ def run(command)
19
+ # stdout, stderr pipes
20
+ rout, wout = IO.pipe
21
+ rerr, werr = IO.pipe
22
+
23
+ result = OpenStruct.new
24
+
25
+ begin
26
+ result.pid = Process.spawn(command, :out => wout, :err => werr)
27
+ _, status = Timeout::timeout(timeout) { Process.wait2(result.pid) }
28
+
29
+ result.status = status.exitstatus
30
+ rescue Timeout::Error
31
+ Process.kill 'KILL', result.pid
32
+ result.status = 99
33
+ end
34
+
35
+ # close write ends so we could read them
36
+ wout.close
37
+ werr.close
38
+
39
+ result.stdout = rout.readlines
40
+ result.stderr = rerr.readlines
41
+
42
+ # dispose the read ends of the pipes
43
+ rout.close
44
+ rerr.close
45
+
46
+ result
47
+ end
48
+ end
49
+ end
50
+
51
+ module TestServer
52
+ module RunCommand
53
+ def run_command(command, timeout: 5)
54
+ runner = CommandRunner.new(timeout: timeout)
55
+ runner.run(command)
56
+ end
57
+ end
58
+ end
@@ -41,5 +41,8 @@ module TestServer
41
41
 
42
42
  # raised if developer misses to define action for controller in parameter list
43
43
  class ActionNotDefinedInParameterList < InternalError; end
44
+
45
+ # raised if developer misses to define role
46
+ class RoleNotDefined < InternalError; end
44
47
  end
45
48
  end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ class FileSize
4
+ attr_accessor :value, :suffix
5
+
6
+ def initialize(value:, suffix:)
7
+ @value = value
8
+ @suffix = suffix
9
+ end
10
+
11
+ def to_s
12
+ "#{value} #{suffix}"
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class FiletypeDetector
4
+ private
5
+
6
+ attr_reader :engine
7
+
8
+ public
9
+
10
+ def initialize(engine: FileMagic.new)
11
+ @engine = engine
12
+ end
13
+
14
+ def use(file)
15
+ file.filetype = engine.file(file.path)
16
+ rescue StandardError => err
17
+ Rails.logger.error "#{err.class}: #{err.message}"
18
+ file.filetype = "An error occured while determine file type for \"#{file.name}\"."
19
+ end
20
+ end
21
+ end
@@ -49,6 +49,7 @@ en:
49
49
  reset: 'Reset'
50
50
  close: 'Close'
51
51
  clone: 'Clone'
52
+ upload: 'Upload'
52
53
  dialogs:
53
54
  notification:
54
55
  title: Notification
@@ -105,6 +106,33 @@ en:
105
106
  index:
106
107
  title: Overview for Reflectors
107
108
  link: Overview
109
+ file_uploader:
110
+ title: File Uploader
111
+ link: File Uploader
112
+ index:
113
+ title: Overview for File Uploads
114
+ link: Overview
115
+ result:
116
+ title: "Information about %{file}"
117
+ link: "%{file}"
118
+ fields:
119
+ file: File
120
+ checksum: Checksums
121
+ filename: Filename
122
+ virus: Virus ID
123
+ filetype: Filetype
124
+ size: Size
125
+ upload:
126
+ title: Upload file
127
+ link: Upload file
128
+ fields:
129
+ file: File
130
+ virus_scan: Scan for viruses
131
+ filetype_detection: Detect filetype
132
+ checksum_calculation: Calculate Checksums
133
+ spinner:
134
+ text: Waiting for upload to finish...
135
+
108
136
  static:
109
137
  link: Static
110
138
  title: Static content
@@ -134,4 +162,3 @@ en:
134
162
  status: Status
135
163
  spinner:
136
164
  text: Waiting for results...
137
-
@@ -14,7 +14,12 @@ module TestServer
14
14
  TestServer.ui_logger.info "Activating debug mode."
15
15
 
16
16
  require 'pry'
17
- require 'debugger'
17
+ if RUBY_VERSION < '2.0.0'
18
+ require 'debugger'
19
+ else
20
+ require 'byebug'
21
+ end
22
+
18
23
  rescue LoadError
19
24
  TestServer.ui_logger.error "You tried to enable debug-mode, but either 'pry'- or 'debugger'-gem are not installed. Please fix that before using the debug-switch again."
20
25
  end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class MD5Calculator < ChecksumCalculator
4
+ private
5
+
6
+ attr_reader :engine
7
+
8
+ def compute_checksum(file)
9
+ Checksum.new(
10
+ algorithm: :md5,
11
+ prefix: 'MD5',
12
+ engine: Digest::MD5,
13
+ data: File.read(file.path),
14
+ )
15
+ end
16
+ end
17
+ end
@@ -13,7 +13,9 @@ module TestServer
13
13
  @params = params
14
14
 
15
15
  @database = {
16
+ # controller name
16
17
  dashboard: {
18
+ # action: role1, role2, ...
17
19
  show: [],
18
20
  },
19
21
  reflector: {
@@ -40,6 +42,11 @@ module TestServer
40
42
  xhr: [:generatable, :repeatable],
41
43
  index: [],
42
44
  },
45
+ file_uploader: {
46
+ upload: [],
47
+ result: [:uploadable],
48
+ index: [],
49
+ },
43
50
  }
44
51
  end
45
52
 
@@ -47,8 +54,8 @@ module TestServer
47
54
  name = name.to_sym
48
55
  action = action.to_sym
49
56
 
50
- raise Exceptions::ControllerNotDefinedInParameterList unless database.key? name
51
- raise Exceptions::ActionNotDefinedInParameterList unless database[name].key? action
57
+ raise Exceptions::ControllerNotDefinedInParameterList, JSON.dump(name: name) unless database.key? name
58
+ raise Exceptions::ActionNotDefinedInParameterList, JSON.dump(action: action) unless database[name].key? action
52
59
 
53
60
  generate_params(defaults, params_for(database[name][action]))
54
61
  end
@@ -65,15 +72,22 @@ module TestServer
65
72
 
66
73
  private
67
74
 
75
+ def validate_role(role)
76
+ raise Exceptions::RoleNotDefined, JSON.dump(role: role, required_method: :"#{role}_params") unless self.respond_to? :"#{role}_params", true
77
+ end
78
+
79
+ def determine_attributes(role)
80
+ send :"#{role}_params"
81
+ end
82
+
68
83
  def params_for(*roles)
69
84
  roles = roles.flatten
70
85
  attributes = Set.new
71
86
 
72
- attributes = attributes + countable_params if roles.include? :countable
73
- attributes = attributes + encodable_params if roles.include? :encodable
74
- attributes = attributes + cachable_params if roles.include? :cachable
75
- attributes = attributes + repeatable_params if roles.include? :repeatable
76
- attributes = attributes + generatable_params if roles.include? :generatable
87
+ roles.each do |r|
88
+ validate_role r
89
+ attributes += determine_attributes(r)
90
+ end
77
91
 
78
92
  attributes
79
93
  end
@@ -107,5 +121,9 @@ module TestServer
107
121
  def cachable_params
108
122
  [:expires]
109
123
  end
124
+
125
+ def uploadable_params
126
+ [:authenticity_token, :file, :upload, { test_server_file_upload: [ :uploaded_file, :virus_scan, :filetype_detection, :checksum_calculation ] }, :utf8]
127
+ end
110
128
  end
111
129
  end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class Sha256Calculator < ChecksumCalculator
4
+ private
5
+
6
+ attr_reader :engine
7
+
8
+ def compute_checksum(file)
9
+ Checksum.new(
10
+ algorithm: :sha256,
11
+ prefix: 'SHA256',
12
+ engine: Digest::SHA256,
13
+ data: File.read(file.path),
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class UploadedFile
4
+ private
5
+
6
+ attr_reader :uploaded_file
7
+
8
+ public
9
+
10
+ attr_accessor :filetype, :virus_id, :checksum
11
+
12
+ def initialize(uploaded_file)
13
+ if uploaded_file.respond_to? :tempfile
14
+ @uploaded_file = uploaded_file
15
+ else
16
+ @uploaded_file = OpenStruct.new
17
+ end
18
+
19
+ @checksum = []
20
+ end
21
+
22
+ def checksum=(sum)
23
+ @checksum << sum
24
+ end
25
+
26
+ def path
27
+ uploaded_file.path.to_s
28
+ end
29
+
30
+ def name
31
+ File.basename(uploaded_file.original_filename.to_s)
32
+ end
33
+
34
+ def has_filetype?
35
+ !filetype.blank?
36
+ end
37
+
38
+ def contains_virus?
39
+ !virus_id.blank?
40
+ end
41
+
42
+ def has_checksum?
43
+ !checksum.blank?
44
+ end
45
+
46
+ def size
47
+ formula = lambda { |number| uploaded_file.size.to_f / (2**number) }
48
+
49
+ result = {}
50
+ result[:b] = FileSize.new(suffix: 'B', value: uploaded_file.size.to_s)
51
+ result[:kib] = FileSize.new(suffix: 'KiB', value: '%.2f' % formula.call(10))
52
+ result[:mib] = FileSize.new(suffix: 'MiB', value: '%.2f' % formula.call(20))
53
+ result[:gib] = FileSize.new(suffix: 'KiB', value: '%.2f' % formula.call(30))
54
+
55
+ result
56
+ end
57
+ end
58
+ end
@@ -1,4 +1,4 @@
1
1
  #main TestServer
2
2
  module TestServer
3
- VERSION = '0.4.1'
3
+ VERSION = '0.5.0'
4
4
  end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ module TestServer
3
+ class VirusDetector
4
+
5
+ private
6
+
7
+ attr_reader :command, :timeout
8
+
9
+ public
10
+
11
+ def initialize(command: which('clamdscan'))
12
+ @command = command
13
+ @timeout = 60
14
+ end
15
+
16
+ def use(file)
17
+ file.virus_id = scan(file)
18
+ end
19
+
20
+ private
21
+
22
+ include FeduxOrg::Stdlib::Command::Which
23
+ include TestServer::RunCommand
24
+
25
+ def scan(file)
26
+ return "Scan commands \"clamdscan\" and \"clamscan\" not found. File \"#{file.name}\" could not be scanned." if command.blank?
27
+
28
+ result = run_command("#{command} #{file.path}", timeout: timeout)
29
+ return "Timeout \"#{timeout}\" reached before finishing scan." if result.status == 99
30
+ return "Scan failed due to error: #{extract_error(result.stdout)}" if result.stdout.first['ERROR']
31
+
32
+ extract_virus_id(result.stdout)
33
+ end
34
+
35
+ def extract_error(data)
36
+ data.first.chomp.split(/:/).last
37
+ end
38
+
39
+ def extract_virus_id(data)
40
+ data.first.scan(/^[^:]+:\s([[:alnum:]-]+)\s[[:alpha:]]+/).flatten.first
41
+ end
42
+ end
43
+ end
data/lib/test_server.rb CHANGED
@@ -17,6 +17,9 @@ require 'base64'
17
17
  require 'thor'
18
18
  require 'zlib'
19
19
  require 'digest/sha1'
20
+ require 'timeout'
21
+ require 'filemagic'
22
+ require 'securerandom'
20
23
 
21
24
  require 'active_support/core_ext/kernel/reporting'
22
25
  require 'active_support/core_ext/object/blank'
@@ -24,6 +27,8 @@ require 'active_support/core_ext/array/access'
24
27
  require 'active_support/core_ext/hash/keys'
25
28
  require 'active_support/core_ext/string/inflections'
26
29
 
30
+ require 'fedux_org/stdlib/command/which'
31
+
27
32
  require 'timeout'
28
33
  require 'logger'
29
34
  require 'pager'
@@ -68,6 +73,16 @@ require 'test_server/server_commands/puma'
68
73
  require 'test_server/server_commands/rackup'
69
74
  require 'test_server/server'
70
75
 
76
+ require 'test_server/command_runner'
77
+ require 'test_server/file_size'
78
+ require 'test_server/uploaded_file'
79
+ require 'test_server/virus_detector'
80
+ require 'test_server/filetype_detector'
81
+ require 'test_server/checksum'
82
+ require 'test_server/checksum_calculator'
83
+ require 'test_server/sha256_calculator'
84
+ require 'test_server/md5_calculator'
85
+
71
86
  require 'test_server/cli/helper'
72
87
  require 'test_server/cli/reload'
73
88
  require 'test_server/cli/main'