vncrec 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3feee74e40b84f5e30207f99e01b2444f8f18d54
4
- data.tar.gz: 2da896794d70531e284c14b369e6f21c5c9085c1
3
+ metadata.gz: b496fdd1cf4345a163978a601c2f3defa77e4646
4
+ data.tar.gz: 205b7ca582a47c89da2e220d77fc5e6b4dc7f2b8
5
5
  SHA512:
6
- metadata.gz: 0c5ed155f4838c12c0b3a1b3288cd9b71c8526f6e04e2628187745b6bcd5ab02954e9a96816f3fa7cac5ac850345a31813ef116f173de96c949d3aef3100dcb5
7
- data.tar.gz: 1c7e9cd361f129e87c298caaebecb70526a6767d49a877356e80e4931001ad5adbe41f37219ea61456d7eed2bcd1ef8d201e9f7570a35bf2cd06f5d47b3413b6
6
+ metadata.gz: 8aeb8c8cd064a12dc28897625cefd801559fd1b920c7afe1a9970848388fd17d8e0473a8723b8407e329cd7d16abdff1a153dd7bcc50c54bc7099c01cbff2947
7
+ data.tar.gz: 6b3bcfb25adc7581a1a90c1a3b7103501a081329c473e05af99851f0338f1258f89fb583bede9a3f6684ae3c7fb2bdfb3162ad7e1226e6d5016355ec5b2a7775
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ##1.0.4
4
+
5
+ * Added authentication
6
+
7
+ ##1.0.3
8
+
3
9
  ##1.0.2
4
10
 
5
11
  * Fixed crash caused by sending `USR1` when `Writer` is not initialized
data/README.md CHANGED
@@ -4,6 +4,10 @@ VNCRec
4
4
  VNCRec is a gem that provides you
5
5
  tools to record VNC session.
6
6
 
7
+ ##Installation
8
+
9
+ `gem install vncrec`
10
+
7
11
  ##Usage
8
12
  There is a binary called `vncrec`, which is a recorder tool.
9
13
 
data/bin/vncrec CHANGED
@@ -64,6 +64,10 @@ OptionParser.new do |opts|
64
64
  opts.on('-s', '--server SERVER', 'Specify host address') do |s|
65
65
  options[:host] = s
66
66
  end
67
+
68
+ opts.on('--password PASSWORD', 'Specify password to use') do |s|
69
+ options[:auth] = [VNCRec::RFB::Authentication::VncAuthentication, s]
70
+ end
67
71
  end.parse!
68
72
 
69
73
  v = VNCRec::Recorder.new(options)
data/examples/auth.rb ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Authentication example.
5
+ # Currently only VNC Authentication type is supported.
6
+ # This type of auth should not be used over untrusted networks,
7
+ # because it uses DES in ECB mode.
8
+ #
9
+ # auth option is an Array. Either
10
+ # [VNCRec::RFB::Authentication::None] (default) or
11
+ # [VNCRec::RFB::Authentication::VncAuthentication, 'mypassword']
12
+
13
+ require 'vncrec'
14
+
15
+ VNCRec::Recorder.new(
16
+ encoding: VNCRec::EncHextile,
17
+ filename: 'file.mp4',
18
+ auth: [VNCRec::RFB::Authentication::VncAuthentication, 'mypassword']
19
+ )
20
+
@@ -13,6 +13,7 @@ end
13
13
 
14
14
  require 'vncrec/constants.rb'
15
15
  require 'vncrec/rfb/proxy.rb'
16
+ require 'vncrec/rfb/authentication.rb'
16
17
  require 'vncrec/writers.rb'
17
18
 
18
19
  module VNCRec
@@ -20,13 +21,14 @@ module VNCRec
20
21
 
21
22
  class Recorder
22
23
  DEFAULTS = {
23
- :pix_fmt => :BGR8,
24
- :debug => nil,
25
- :encoding => VNCRec::ENC_RAW,
26
- :filename => nil,
27
- :fps => 6,
28
- :input => nil,
29
- :port => 5900
24
+ :pix_fmt => :BGR8,
25
+ :debug => nil,
26
+ :encoding => VNCRec::ENC_RAW,
27
+ :filename => nil,
28
+ :fps => 6,
29
+ :input => nil,
30
+ :port => 5900,
31
+ :auth => [VNCRec::RFB::Authentication::None]
30
32
  }
31
33
 
32
34
  # @param geometry [String] geometry of the screen area to capture(+x,y offset is not implemented yet)
@@ -62,6 +64,9 @@ module VNCRec
62
64
 
63
65
  @client = nil
64
66
 
67
+ @auth = options[:auth]
68
+ @password = options[:password]
69
+
65
70
  @framerate = options[:fps]
66
71
  fail ArgumentError if !@framerate.is_a?(Numeric) || @framerate <= 0
67
72
 
@@ -164,7 +169,7 @@ module VNCRec
164
169
  @logger.info 'got client' if @logging
165
170
 
166
171
  end
167
- @client = VNCRec::RFB::Proxy.new(@server, 'RFB 003.008', @enc, @pix_fmt)
172
+ @client = VNCRec::RFB::Proxy.new(@server, 'RFB 003.008', @enc, @pix_fmt, @auth)
168
173
  @recording_starttime = Time.now if @filename.include?('DATE')
169
174
 
170
175
  w, h, name = @client.handshake
@@ -0,0 +1,180 @@
1
+ module VNCRec
2
+ module RFB
3
+ module Authentication
4
+ class Abstract
5
+ def initialize(io, *args)
6
+ @io = io
7
+ end
8
+
9
+ def to_msg
10
+ [@code].pack('C')
11
+ end
12
+
13
+ def handshake
14
+ types = get_security_types
15
+ handle_types(types)
16
+ send_type
17
+ perform_authentication
18
+ security_result
19
+ end
20
+
21
+ # Once the protocol version has been decided, the server and client
22
+ # must agree on the type of security to be used on the connection. The
23
+ # server lists the security types that it supports:
24
+ #
25
+ # +--------------------------+-------------+--------------------------+
26
+ # | No. of bytes | Type | Description |
27
+ # | | [Value] | |
28
+ # +--------------------------+-------------+--------------------------+
29
+ # | 1 | U8 | number-of-security-types |
30
+ # | number-of-security-types | U8 array | security-types |
31
+ # +--------------------------+-------------+--------------------------+
32
+ # If the server listed at least one valid security type supported by
33
+ # the client, the client sends back a single byte indicating which
34
+ # security type is to be used on the connection:
35
+ #
36
+ # +--------------+--------------+---------------+
37
+ # | No. of bytes | Type [Value] | Description |
38
+ # +--------------+--------------+---------------+
39
+ # | 1 | U8 | security-type |
40
+ # +--------------+--------------+---------------+
41
+ #
42
+ # If number-of-security-types is zero, then for some reason the
43
+ # connection failed (e.g., the server cannot support the desired
44
+ # protocol version). This is followed by a string describing the
45
+ # reason (where a string is specified as a length followed by that many
46
+ # ASCII characters):
47
+ #
48
+ # +---------------+--------------+---------------+
49
+ # | No. of bytes | Type [Value] | Description |
50
+ # +---------------+--------------+---------------+
51
+ # | 4 | U32 | reason-length |
52
+ # | reason-length | U8 array | reason-string |
53
+ # +---------------+--------------+---------------+
54
+ #
55
+ # The server closes the connection after sending the reason-string.
56
+ # @return [Integer] types
57
+ def get_security_types
58
+ num_of_st = @io.readbyte
59
+ if num_of_st == 0 # failed
60
+ reason_len = @io.readpartial(4).unpack('L>')[0]
61
+ reason = @io.readpartial(reason_len)
62
+ raise reason
63
+ else
64
+ result = []
65
+ num_of_st.times do
66
+ result << @io.readbyte
67
+ end
68
+ result
69
+ end
70
+ end
71
+
72
+ def handle_types(types)
73
+ raise 'The server does not support requested auth method' unless types.include? @code
74
+ end
75
+
76
+ # If the server listed at least one valid security type supported by
77
+ # the client, the client sends back a single byte indicating which
78
+ # security type is to be used on the connection.
79
+ def send_type
80
+ @io.syswrite to_msg
81
+ end
82
+
83
+ # The server sends a word to inform the client whether the security
84
+ # handshaking was successful.
85
+ #
86
+ # +--------------+--------------+-------------+
87
+ # | No. of bytes | Type [Value] | Description |
88
+ # +--------------+--------------+-------------+
89
+ # | 4 | U32 | status: |
90
+ # | | 0 | OK |
91
+ # | | 1 | failed |
92
+ # +--------------+--------------+-------------+
93
+ #
94
+ # If unsuccessful, the server sends a string describing the reason for
95
+ # the failure, and then closes the connection:
96
+ #
97
+ # +---------------+--------------+---------------+
98
+ # | No. of bytes | Type [Value] | Description |
99
+ # +---------------+--------------+---------------+
100
+ # | 4 | U32 | reason-length |
101
+ # | reason-length | U8 array | reason-string |
102
+ # +---------------+--------------+---------------+
103
+ #
104
+ def security_result
105
+ word = (@io.readpartial 4).unpack('L>').first
106
+ if word != 0
107
+ reason_len = (@io.readpartial 4).unpack('L>').first
108
+ reason = @io.readpartial(reason_len)
109
+ raise reason
110
+ end
111
+ end
112
+
113
+ def perform_authentication
114
+ raise 'NI'
115
+ end
116
+ end
117
+
118
+ class None < Abstract
119
+ def initialize(io, *args)
120
+ super
121
+ @code = 1
122
+ end
123
+
124
+ def perform_authentication
125
+ end
126
+ end
127
+
128
+ class VncAuthentication < Abstract
129
+ def initialize(io, *args)
130
+ super
131
+ @code = 2
132
+ @password = args.first
133
+ end
134
+
135
+ # The server sends a random 16-byte challenge:
136
+ #
137
+ # +--------------+--------------+-------------+
138
+ # | No. of bytes | Type [Value] | Description |
139
+ # +--------------+--------------+-------------+
140
+ # | 16 | U8 | challenge |
141
+ # +--------------+--------------+-------------+
142
+ #
143
+ # The client encrypts the challenge with DES (ECB), using a password supplied
144
+ # by the user as the key. To form the key, the password is truncated
145
+ # to eight characters, or padded with null bytes on the right.
146
+ # Actually, each byte is also reversed. Challenge string is split
147
+ # in two chunks of 8 bytes, which are encrypted separately and clashed together
148
+ # again. The client then sends the resulting 16-byte response:
149
+ #
150
+ # +--------------+--------------+-------------+
151
+ # | No. of bytes | Type [Value] | Description |
152
+ # +--------------+--------------+-------------+
153
+ # | 16 | U8 | response |
154
+ # +--------------+--------------+-------------+
155
+ #
156
+ # The protocol continues with the SecurityResult message.
157
+ def perform_authentication
158
+ require 'openssl'
159
+
160
+ challenge = @io.readpartial(16)
161
+ split_challenge = [challenge.slice(0, 8), challenge.slice(8, 8)]
162
+
163
+ cipher = OpenSSL::Cipher::DES.new(:ECB)
164
+ cipher.encrypt
165
+ cipher.key = normalized_password
166
+ encrypted = split_challenge.reduce('') { |a, e| cipher.reset; a << cipher.update(e) }
167
+ @io.syswrite encrypted
168
+ end
169
+
170
+ private
171
+
172
+ def normalized_password
173
+ rev = ->(n) { (0...8).reduce(0) { |a, e| a + 2**e * n[7 - e] } }
174
+ inv = @password.each_byte.map { |b| rev[b].chr }.join
175
+ inv.ljust(8, "\x00")
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -18,15 +18,20 @@ module VNCRec
18
18
  # @param pf [Hash] pixel format:
19
19
  # * {VNCRec::PIX_FMT_BGR8} - 8 bits per pixel
20
20
  # * {VNCRec::PIX_FMT_BGR32} - 32 bits per pixel
21
- # @param w width of the screen area
22
- # @param h height of the screen area
23
- def initialize(io, rfbv, enc, pf)
21
+ # @param auth [Array]:
22
+ # * Constant class e.g. VNCRec::Authentication::VncAuthentication
23
+ # * optional argument, e.g. password string
24
+ def initialize(io, rfbv, enc, pf, auth)
24
25
  @io = io
25
26
  @version = rfbv
26
27
  @enc = enc
27
28
  @pf = pf
29
+ @auth = auth.first.new(@io, *auth.drop(1))
28
30
  end
29
31
 
32
+ # @param w width of the screen area
33
+ # @param h height of the screen area
34
+ # @param bpp bits per pixel
30
35
  def prepare_framebuffer(w, h, bpp)
31
36
  @w = w
32
37
  @h = h
@@ -43,24 +48,10 @@ module VNCRec
43
48
  version = @io.readpartial 12
44
49
  @io.syswrite(@version + "\n")
45
50
 
46
- # security
47
- num_of_st = @io.readbyte
48
- if num_of_st == 0 # failed
49
- reason_len = @io.readpartial(4).unpack('L>')[0]
50
- reason = @io.readpartial(reason_len)
51
- fail reason
52
- else
53
- num_of_st.times do
54
- @io.readbyte
55
- end
56
- end
57
-
58
- reply = [1].pack('C') # security type:none
59
- @io.syswrite reply
51
+ @auth.handshake
60
52
 
61
- stype = (@io.readpartial 4).unpack('H' * 8)
62
53
  # client init
63
- @io.syswrite reply
54
+ @io.syswrite "\x01"
64
55
 
65
56
  # server init
66
57
  w = @io.readpartial(2).unpack('S>')[0]
@@ -69,8 +60,6 @@ module VNCRec
69
60
  nlen = @io.readpartial(4).unpack('L>')[0]
70
61
  @name = @io.readpartial nlen
71
62
  return [w, h, @name]
72
- rescue
73
- return nil
74
63
  end
75
64
 
76
65
  # Set a way that server should use to represent pixel data
@@ -1,3 +1,3 @@
1
1
  module VNCRec
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  end
data/vncrec.gemspec CHANGED
@@ -28,6 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'rspec'
29
29
  spec.add_development_dependency 'rspec-its'
30
30
  spec.add_development_dependency 'activesupport'
31
+ spec.add_development_dependency 'pry'
32
+ spec.add_development_dependency 'pry-byebug'
31
33
 
32
34
  spec.requirements << 'ffmpeg'
33
35
  spec.requirements << 'x11vnc'
metadata CHANGED
@@ -1,97 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vncrec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - d-theus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-05 00:00:00.000000000 Z
11
+ date: 2017-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.7'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake-compiler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-its
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activesupport
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry-byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0'
97
125
  description: |-
@@ -106,14 +134,15 @@ extensions:
106
134
  - ext/enchex_c/extconf.rb
107
135
  extra_rdoc_files: []
108
136
  files:
109
- - .gitignore
110
- - .rspec
137
+ - ".gitignore"
138
+ - ".rspec"
111
139
  - CHANGELOG.md
112
140
  - Gemfile
113
141
  - LICENSE.txt
114
142
  - README.md
115
143
  - Rakefile
116
144
  - bin/vncrec
145
+ - examples/auth.rb
117
146
  - examples/exit.rb
118
147
  - examples/mp4.rb
119
148
  - examples/mp4audio.rb
@@ -122,6 +151,7 @@ files:
122
151
  - lib/vncrec.rb
123
152
  - lib/vncrec/constants.rb
124
153
  - lib/vncrec/recorder.rb
154
+ - lib/vncrec/rfb/authentication.rb
125
155
  - lib/vncrec/rfb/enchex.rb
126
156
  - lib/vncrec/rfb/encraw.rb
127
157
  - lib/vncrec/rfb/enczrle.rb
@@ -143,19 +173,19 @@ require_paths:
143
173
  - lib
144
174
  required_ruby_version: !ruby/object:Gem::Requirement
145
175
  requirements:
146
- - - '>='
176
+ - - ">="
147
177
  - !ruby/object:Gem::Version
148
178
  version: '0'
149
179
  required_rubygems_version: !ruby/object:Gem::Requirement
150
180
  requirements:
151
- - - '>='
181
+ - - ">="
152
182
  - !ruby/object:Gem::Version
153
183
  version: '0'
154
184
  requirements:
155
185
  - ffmpeg
156
186
  - x11vnc
157
187
  rubyforge_project:
158
- rubygems_version: 2.0.14
188
+ rubygems_version: 2.4.5.2
159
189
  signing_key:
160
190
  specification_version: 4
161
191
  summary: VNC session recording