test_server 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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'