vncrec 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +4 -0
- data/bin/vncrec +4 -0
- data/examples/auth.rb +20 -0
- data/lib/vncrec/recorder.rb +13 -8
- data/lib/vncrec/rfb/authentication.rb +180 -0
- data/lib/vncrec/rfb/proxy.rb +10 -21
- data/lib/vncrec/version.rb +1 -1
- data/vncrec.gemspec +2 -0
- metadata +49 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b496fdd1cf4345a163978a601c2f3defa77e4646
|
4
|
+
data.tar.gz: 205b7ca582a47c89da2e220d77fc5e6b4dc7f2b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8aeb8c8cd064a12dc28897625cefd801559fd1b920c7afe1a9970848388fd17d8e0473a8723b8407e329cd7d16abdff1a153dd7bcc50c54bc7099c01cbff2947
|
7
|
+
data.tar.gz: 6b3bcfb25adc7581a1a90c1a3b7103501a081329c473e05af99851f0338f1258f89fb583bede9a3f6684ae3c7fb2bdfb3162ad7e1226e6d5016355ec5b2a7775
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
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
|
+
|
data/lib/vncrec/recorder.rb
CHANGED
@@ -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
|
24
|
-
:debug
|
25
|
-
:encoding
|
26
|
-
:filename
|
27
|
-
:fps
|
28
|
-
:input
|
29
|
-
:port
|
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
|
data/lib/vncrec/rfb/proxy.rb
CHANGED
@@ -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
|
22
|
-
#
|
23
|
-
|
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
|
-
|
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
|
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
|
data/lib/vncrec/version.rb
CHANGED
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.
|
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:
|
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.
|
188
|
+
rubygems_version: 2.4.5.2
|
159
189
|
signing_key:
|
160
190
|
specification_version: 4
|
161
191
|
summary: VNC session recording
|