ruby-vnc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2008-08-29
2
+
3
+ - First public release
4
+
data/README ADDED
@@ -0,0 +1,26 @@
1
+ = Introduction
2
+
3
+ The ruby-vnc library provides for simple rfb-protocol based control of a
4
+ VNC server. This can be used, eg, to automate applications (sometimes there
5
+ is no better way), or script some sort of interaction.
6
+
7
+ Being VNC based gives it the advantage of being able to be run against
8
+ servers on any platform.
9
+
10
+ The primary documentation is for the Net::VNC class.
11
+
12
+ = Thanks
13
+
14
+ Code borrows a lot from Tim Waugh's excellent rfbplaymacro. So far all it
15
+ really offers on top of that is access to the host clipboard, and the ease
16
+ with which it can be scripted, ie taking conditional actions based on the
17
+ contents thereof.
18
+
19
+ = TODO
20
+
21
+ * Having the ability to take and analyse screen dumps would be useful.
22
+
23
+ * Finish the specs.
24
+
25
+ * Fix issues with the way we use a background thread to handle the clipboard
26
+ etc chatter from the server.
@@ -0,0 +1,83 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'spec/rake/spectask'
5
+ require 'spec/rake/verify_rcov'
6
+
7
+ require File.dirname(__FILE__) + '/lib/net/vnc/version'
8
+
9
+ PKG_NAME = 'ruby-vnc'
10
+ PKG_VERSION = Net::VNC::VERSION
11
+
12
+ task :default => :spec
13
+
14
+ desc 'Run all specs'
15
+ Spec::Rake::SpecTask.new :spec do |t|
16
+ t.spec_opts = ['--format specdoc --colour']
17
+ end
18
+
19
+ desc 'Run all specs and generate html spec document'
20
+ namespace :spec do
21
+ Spec::Rake::SpecTask.new :html do |t|
22
+ t.spec_opts = ['--format html:spec.html']
23
+ end
24
+ end
25
+
26
+ desc 'Run all specs and generate coverage'
27
+ Spec::Rake::SpecTask.new :rcov do |t|
28
+ t.rcov = true
29
+ t.rcov_opts = ['--exclude', 'spec']
30
+ t.rcov_opts << '--xrefs'
31
+ t.rcov_opts << '--text-report'
32
+ end
33
+
34
+ namespace :rcov do
35
+ RCov::VerifyTask.new :verify => :rcov do |t|
36
+ t.threshold = 100.0
37
+ t.index_html = 'coverage/index.html'
38
+ end
39
+ end
40
+
41
+ Rake::RDocTask.new do |t|
42
+ t.rdoc_dir = 'doc'
43
+ t.rdoc_files.include 'lib/**/*.rb'
44
+ t.rdoc_files.include 'README'
45
+ t.title = "#{PKG_NAME} documentation"
46
+ t.options += %w[--line-numbers --inline-source --tab-width 2]
47
+ t.main = 'README'
48
+ end
49
+
50
+ spec = Gem::Specification.new do |s|
51
+ s.name = PKG_NAME
52
+ s.version = PKG_VERSION
53
+ s.summary = %q{Ruby VNC library.}
54
+ s.description = %q{A library which implements the client VNC protocol to control VNC servers.}
55
+ s.authors = ['Charles Lowe']
56
+ s.email = %q{aquasync@gmail.com}
57
+ # not yet registered
58
+ #s.homepage = %q{http://code.google.com/p/ruby-vnc}
59
+ #s.rubyforge_project = %q{ruby-vnc}
60
+
61
+ # none yet
62
+ #s.executables = ['oletool']
63
+ s.files = ['Rakefile', 'README', 'ChangeLog', 'data/keys.yaml']
64
+ s.files += FileList['lib/**/*.rb']
65
+ s.files += FileList['spec/*_spec.rb']
66
+ # is there an rspec equivalent?
67
+ #s.test_files = FileList['test/test_*.rb']
68
+
69
+ s.has_rdoc = true
70
+ s.rdoc_options += [
71
+ '--main', 'README',
72
+ '--title', "#{PKG_NAME} documentation",
73
+ '--tab-width', '2'
74
+ ]
75
+ end
76
+
77
+ Rake::GemPackageTask.new(spec) do |t|
78
+ t.gem_spec = spec
79
+ t.need_tar = false
80
+ t.need_zip = false
81
+ t.package_dir = 'build'
82
+ end
83
+
@@ -0,0 +1,128 @@
1
+ backspace: 0xff08
2
+ tab: 0xff09
3
+ linefeed: 0xff0a
4
+ clear: 0xff0b
5
+ return: 0xff0d
6
+ pause: 0xff13
7
+ scroll_lock: 0xff14
8
+ sys_req: 0xff15
9
+ escape: 0xff1b
10
+ delete: 0xffff
11
+ home: 0xff50
12
+ left: 0xff51
13
+ up: 0xff52
14
+ right: 0xff53
15
+ down: 0xff54
16
+ prior: 0xff55
17
+ page_up: 0xff55
18
+ next: 0xff56
19
+ page_down: 0xff56
20
+ end: 0xff57
21
+ begin: 0xff58
22
+ select: 0xff60
23
+ print: 0xff61
24
+ execute: 0xff62
25
+ insert: 0xff63
26
+ undo: 0xff65
27
+ redo: 0xff66
28
+ menu: 0xff67
29
+ find: 0xff68
30
+ cancel: 0xff69
31
+ help: 0xff6a
32
+ break: 0xff6b
33
+ mode_switch: 0xff7e
34
+ script_switch: 0xff7e
35
+ num_lock: 0xff7f
36
+ kp_space: 0xff80
37
+ kp_tab: 0xff89
38
+ kp_enter: 0xff8d
39
+ kp_f1: 0xff91
40
+ kp_f2: 0xff92
41
+ kp_f3: 0xff93
42
+ kp_f4: 0xff94
43
+ kp_home: 0xff95
44
+ kp_left: 0xff96
45
+ kp_up: 0xff97
46
+ kp_right: 0xff98
47
+ kp_down: 0xff99
48
+ kp_prior: 0xff9a
49
+ kp_page_up: 0xff9a
50
+ kp_next: 0xff9b
51
+ kp_page_down: 0xff9b
52
+ kp_end: 0xff9c
53
+ kp_begin: 0xff9d
54
+ kp_insert: 0xff9e
55
+ kp_delete: 0xff9f
56
+ kp_equal: 0xffbd
57
+ kp_multiply: 0xffaa
58
+ kp_add: 0xffab
59
+ kp_separator: 0xffac
60
+ kp_subtract: 0xffad
61
+ kp_decimal: 0xffae
62
+ kp_divide: 0xffaf
63
+ kp_0: 0xffb0
64
+ kp_1: 0xffb1
65
+ kp_2: 0xffb2
66
+ kp_3: 0xffb3
67
+ kp_4: 0xffb4
68
+ kp_5: 0xffb5
69
+ kp_6: 0xffb6
70
+ kp_7: 0xffb7
71
+ kp_8: 0xffb8
72
+ kp_9: 0xffb9
73
+ f1: 0xffbe
74
+ f2: 0xffbf
75
+ f3: 0xffc0
76
+ f4: 0xffc1
77
+ f5: 0xffc2
78
+ f6: 0xffc3
79
+ f7: 0xffc4
80
+ f8: 0xffc5
81
+ f9: 0xffc6
82
+ f10: 0xffc7
83
+ f11: 0xffc8
84
+ f12: 0xffc9
85
+ f13: 0xffca
86
+ f14: 0xffcb
87
+ f15: 0xffcc
88
+ f16: 0xffcd
89
+ f17: 0xffce
90
+ f18: 0xffcf
91
+ f19: 0xffd0
92
+ f20: 0xffd1
93
+ f21: 0xffd2
94
+ f22: 0xffd3
95
+ f23: 0xffd4
96
+ f24: 0xffd5
97
+ f25: 0xffd6
98
+ f26: 0xffd7
99
+ f27: 0xffd8
100
+ f28: 0xffd9
101
+ f29: 0xffda
102
+ f30: 0xffdb
103
+ f31: 0xffdc
104
+ f32: 0xffdd
105
+ f33: 0xffde
106
+ f34: 0xffdf
107
+ f35: 0xffe0
108
+ left_shift: 0xffe1
109
+ right_shift: 0xffe2
110
+ left_control: 0xffe3
111
+ right_control: 0xffe4
112
+ caps_lock: 0xffe5
113
+ shift_lock: 0xffe6
114
+ left_meta: 0xffe7
115
+ right_meta: 0xffe8
116
+ left_alt: 0xffe9
117
+ right_alt: 0xffea
118
+ left_super: 0xffeb
119
+ right_super: 0xffec
120
+ left_hyper: 0xffed
121
+ right_hyper: 0xffee
122
+ # some convenience aliases
123
+ shift: 0xffe1
124
+ control: 0xffe3
125
+ meta: 0xffe7
126
+ alt: 0xffe9
127
+ super: 0xffeb
128
+ hyper: 0xffed
@@ -0,0 +1,439 @@
1
+ module Cipher
2
+ #
3
+ # = Brief
4
+ #
5
+ # The Cipher::DES class allows for encryption and decryption of plain
6
+ # text using the "Data Encryption Standard". This version is the modified
7
+ # version which is part of the VNC authentication scheme.
8
+ #
9
+ # Usage is pretty straight forward:
10
+ #
11
+ # des = Cipher::DES.new 'mysecretkey', :encrypt
12
+ # str = des.update 'plain text'
13
+ # str << des.update 'more plain text'
14
+ # str << final
15
+ #
16
+ # Or just use the shortcut class methods:
17
+ #
18
+ # str = Cipher::DES.encrypt 'mysecretkey', 'plain text'
19
+ #
20
+ # = About
21
+ #
22
+ # This code was ported from the file "d3des.c", for portability reasons.
23
+ # It is not expected to be quick, but is only being used currently for the
24
+ # VNC authentication handshake. If you wanted to cipher a lot of text, you
25
+ # should probably compile the original C as an extension.
26
+ #
27
+ # I've included the following copyright info from the C source verbatim:
28
+ #
29
+ # This is D3DES (V5.09) by Richard Outerbridge with the double and
30
+ # triple-length support removed for use in VNC. Also the bytebit[] array
31
+ # has been reversed so that the most significant bit in each byte of the
32
+ # key is ignored, not the least significant.
33
+ #
34
+ # These changes are:
35
+ # Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
36
+ #
37
+ # This software is distributed in the hope that it will be useful,
38
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
39
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
40
+ #
41
+ # D3DES (V5.09)
42
+ #
43
+ # A portable, public domain, version of the Data Encryption Standard.
44
+ #
45
+ # Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
46
+ # Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
47
+ # code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
48
+ # Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
49
+ # for humouring me on.
50
+ #
51
+ # Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
52
+ # (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
53
+ #
54
+ class DES
55
+ BLOCK_SIZE = 8
56
+
57
+ attr_reader :key, :mode
58
+
59
+ # Create a des cipher object. +key+ should be cipher key to use, and +mode+ should
60
+ # be either <tt>:encrypt</tt> or <tt>:decrypt</tt>.
61
+ #
62
+ # It will expand +key+ to be 8 bytes by padding with null bytes. If it is longer than
63
+ # 8 bytes, the additional data is discarded.
64
+ def initialize key, mode
65
+ unless [:encrypt, :decrypt].include? mode
66
+ raise ArgumentError, 'invalid mode argument - %s' % mode
67
+ end
68
+ @mode = mode
69
+
70
+ # ensure key is 8 bytes. pad with nulls as needed
71
+ key = key[0, BLOCK_SIZE]
72
+ key << 0.chr * (BLOCK_SIZE - key.length)
73
+ @key = key
74
+
75
+ # now expand the key schedule
76
+ @keys = self.class.send :prepare_key_stage2, self.class.send(:prepare_key_stage1, key, mode)
77
+
78
+ # this internal buffer is used because we must process data in chunks of 8 bytes
79
+ @buf = ''
80
+ end
81
+
82
+ # This updates the cipher with +data+, returning any available ciphered output. The +data+ is
83
+ # processed in blocks of 8 bytes, so any residual is added to an internal buffer.
84
+ def update data
85
+ result = ''
86
+ data = @buf + data unless @buf.empty?
87
+ num_blocks, residual = data.length.divmod BLOCK_SIZE
88
+ num_blocks.times do |i|
89
+ block = data[i * BLOCK_SIZE, BLOCK_SIZE].unpack('N2')
90
+ result << self.class.send(:desfunc, block, @keys).pack('N2')
91
+ end
92
+ @buf = residual == 0 ? '' : data[-residual..-1]
93
+ result
94
+ end
95
+
96
+ # This flushes the internal buffer by padding it out with null bytes, and doing a final
97
+ # DES round. Note that this means the ciphered text is always padded out to a multiple of
98
+ # 8 bytes.
99
+ def final
100
+ if @buf.empty?
101
+ ''
102
+ else
103
+ update 0.chr * (BLOCK_SIZE - @buf.length)
104
+ end
105
+ end
106
+
107
+ # A shortcut method to create a cipher object using +key+, and fully encrypt +data+
108
+ def self.encrypt key, data
109
+ des = new key, :encrypt
110
+ des.update(data) << des.final
111
+ end
112
+
113
+ # A shortcut method to create a cipher object using +key+, and fully decrypt +data+
114
+ def self.decrypt key, data
115
+ des = new key, :decrypt
116
+ des.update(data) << des.final
117
+ end
118
+
119
+ class << self #:nodoc: all
120
+ BYTEBIT = [
121
+ 01, 02, 04, 010, 020, 040, 0100, 0200
122
+ ]
123
+
124
+ BIGBYTE = [
125
+ 0x800000, 0x400000, 0x200000, 0x100000,
126
+ 0x080000, 0x040000, 0x020000, 0x010000,
127
+ 0x008000, 0x004000, 0x002000, 0x001000,
128
+ 0x000800, 0x000400, 0x000200, 0x000100,
129
+ 0x000080, 0x000040, 0x000020, 0x000010,
130
+ 0x000008, 0x000004, 0x000002, 0x000001
131
+ ]
132
+
133
+ # Use the key schedule specified in the Standard (ANSI X3.92-1981).
134
+
135
+ PC1 = [
136
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
137
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
138
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
139
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
140
+ ]
141
+
142
+ TOTROT = [
143
+ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
144
+ ]
145
+
146
+ PC2 = [
147
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
148
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
149
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
150
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
151
+ ]
152
+
153
+ private
154
+
155
+ #
156
+ # Prepares +key+ to be used
157
+ #
158
+ # +key+:: String
159
+ # +mode+:: :encrypt or :decrypt
160
+ #
161
+ # Thanks to James Gillogly & Phil Karn!
162
+ #
163
+ # corresponds to "deskey"
164
+ #
165
+ def prepare_key_stage1 key, mode
166
+ pcr = [nil] * 56
167
+ kn = [nil] * 32
168
+
169
+ pc1m = (0...56).map do |j|
170
+ l = PC1[j]
171
+ m = l & 07
172
+ (key[l >> 3] & BYTEBIT[m]) != 0 ? 1 : 0;
173
+ end
174
+
175
+ 16.times do |i|
176
+ m = mode == :encrypt ? i << 1 : (15 - i) << 1
177
+ n = m + 1
178
+ kn[m] = kn[n] = 0
179
+ 28.times do |j|
180
+ l = (j + TOTROT[i]) % 28
181
+ pcr[j] = pc1m[l]
182
+ pcr[j + 28] = pc1m[l + 28]
183
+ end
184
+ 24.times do |j|
185
+ kn[m] |= BIGBYTE[j] if pcr[PC2[j]] != 0
186
+ kn[n] |= BIGBYTE[j] if pcr[PC2[j+24]] != 0
187
+ end
188
+ end
189
+
190
+ kn
191
+ end
192
+
193
+ # corresponds to "cookey"
194
+ def prepare_key_stage2(raw1)
195
+ cook = []
196
+
197
+ 16.times do |i|
198
+ a = raw1[i * 2 + 0]
199
+ b = raw1[i * 2 + 1]
200
+ x = (a & 0x00fc0000) << 6
201
+ x |= (a & 0x00000fc0) << 10
202
+ x |= (b & 0x00fc0000) >> 10
203
+ x |= (b & 0x00000fc0) >> 6
204
+ cook << x
205
+ x = (a & 0x0003f000) << 12
206
+ x |= (a & 0x0000003f) << 16
207
+ x |= (b & 0x0003f000) >> 4
208
+ x |= (b & 0x0000003f)
209
+ cook << x
210
+ end
211
+
212
+ cook
213
+ end
214
+
215
+ SP1 = [
216
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
217
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
218
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
219
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
220
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
221
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
222
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
223
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
224
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
225
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
226
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
227
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
228
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
229
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
230
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
231
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
232
+ ]
233
+
234
+ SP2 = [
235
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
236
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
237
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
238
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
239
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
240
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
241
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
242
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
243
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
244
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
245
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
246
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
247
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
248
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
249
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
250
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
251
+ ]
252
+
253
+ SP3 = [
254
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
255
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
256
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
257
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
258
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
259
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
260
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
261
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
262
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
263
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
264
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
265
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
266
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
267
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
268
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
269
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
270
+ ]
271
+
272
+ SP4 = [
273
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
274
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
275
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
276
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
277
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
278
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
279
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
280
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
281
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
282
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
283
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
284
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
285
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
286
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
287
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
288
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
289
+ ]
290
+
291
+ SP5 = [
292
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
293
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
294
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
295
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
296
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
297
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
298
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
299
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
300
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
301
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
302
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
303
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
304
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
305
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
306
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
307
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
308
+ ]
309
+
310
+ SP6 = [
311
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
312
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
313
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
314
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
315
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
316
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
317
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
318
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
319
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
320
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
321
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
322
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
323
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
324
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
325
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
326
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
327
+ ]
328
+
329
+ SP7 = [
330
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
331
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
332
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
333
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
334
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
335
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
336
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
337
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
338
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
339
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
340
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
341
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
342
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
343
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
344
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
345
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
346
+ ]
347
+
348
+ SP8 = [
349
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
350
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
351
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
352
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
353
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
354
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
355
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
356
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
357
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
358
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
359
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
360
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
361
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
362
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
363
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
364
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
365
+ ]
366
+
367
+ def desfunc block, keys
368
+ leftt = block[0]
369
+ right = block[1]
370
+
371
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0f
372
+ right ^= work
373
+ leftt ^= (work << 4)
374
+ work = ((leftt >> 16) ^ right) & 0x0000ffff
375
+ right ^= work
376
+ leftt ^= (work << 16)
377
+ work = ((right >> 2) ^ leftt) & 0x33333333
378
+ leftt ^= work
379
+ right ^= (work << 2)
380
+ work = ((right >> 8) ^ leftt) & 0x00ff00ff
381
+ leftt ^= work
382
+ right ^= (work << 8)
383
+ right = ((right << 1) | ((right >> 31) & 1)) & 0xffffffff
384
+ work = (leftt ^ right) & 0xaaaaaaaa
385
+ leftt ^= work
386
+ right ^= work
387
+ leftt = ((leftt << 1) | ((leftt >> 31) & 1)) & 0xffffffff
388
+
389
+ 8.times do |i|
390
+ work = (right << 28) | (right >> 4)
391
+ work ^= keys[i * 4 + 0]
392
+ fval = SP7[ work & 0x3f]
393
+ fval |= SP5[(work >> 8) & 0x3f]
394
+ fval |= SP3[(work >> 16) & 0x3f]
395
+ fval |= SP1[(work >> 24) & 0x3f]
396
+ work = right ^ keys[i * 4 + 1]
397
+ fval |= SP8[ work & 0x3f]
398
+ fval |= SP6[(work >> 8) & 0x3f]
399
+ fval |= SP4[(work >> 16) & 0x3f]
400
+ fval |= SP2[(work >> 24) & 0x3f]
401
+ leftt ^= fval
402
+ work = (leftt << 28) | (leftt >> 4)
403
+ work ^= keys[i * 4 + 2]
404
+ fval = SP7[ work & 0x3f]
405
+ fval |= SP5[(work >> 8) & 0x3f]
406
+ fval |= SP3[(work >> 16) & 0x3f]
407
+ fval |= SP1[(work >> 24) & 0x3f]
408
+ work = leftt ^ keys[i * 4 + 3]
409
+ fval |= SP8[ work & 0x3f]
410
+ fval |= SP6[(work >> 8) & 0x3f]
411
+ fval |= SP4[(work >> 16) & 0x3f]
412
+ fval |= SP2[(work >> 24) & 0x3f]
413
+ right ^= fval
414
+ end
415
+
416
+ right = ((right << 31) | (right >> 1)) & 0xffffffff
417
+ work = (leftt ^ right) & 0xaaaaaaaa
418
+ leftt ^= work
419
+ right ^= work
420
+ leftt = ((leftt << 31) | (leftt >> 1)) & 0xffffffff
421
+ work = ((leftt >> 8) ^ right) & 0x00ff00ff
422
+ right ^= work
423
+ leftt ^= (work << 8)
424
+ work = ((leftt >> 2) ^ right) & 0x33333333
425
+ right ^= work
426
+ leftt ^= (work << 2)
427
+ work = ((right >> 16) ^ leftt) & 0x0000ffff
428
+ leftt ^= work
429
+ right ^= (work << 16)
430
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0f
431
+ leftt ^= work
432
+ right ^= (work << 4)
433
+
434
+ [right, leftt]
435
+ end
436
+ end
437
+ end
438
+ end
439
+
@@ -0,0 +1,306 @@
1
+ require 'socket'
2
+ require 'yaml'
3
+ require 'thread'
4
+ require 'cipher/des'
5
+ require 'net/vnc/version'
6
+
7
+ module Net
8
+ #
9
+ # The VNC class provides for simple rfb-protocol based control of
10
+ # a VNC server. This can be used, eg, to automate applications.
11
+ #
12
+ # Sample usage:
13
+ #
14
+ # # launch xclock on localhost. note that there is an xterm in the top-left
15
+ # Net::VNC.open 'localhost:0', :shared => true, :password => 'mypass' do |vnc|
16
+ # vnc.pointer_move 10, 10
17
+ # vnc.type 'xclock'
18
+ # vnc.key_press :return
19
+ # end
20
+ #
21
+ # = TODO
22
+ #
23
+ # * The server read loop seems a bit iffy. Not sure how best to do it.
24
+ # * Should probably be changed to be more of a lower-level protocol wrapping thing, with the
25
+ # actual VNCClient sitting on top of that. all it should do is read/write the packets over
26
+ # the socket.
27
+ #
28
+ class VNC
29
+ class PointerState
30
+ attr_reader :x, :y, :button
31
+
32
+ def initialize vnc
33
+ @x = @y = @button = 0
34
+ @vnc = vnc
35
+ end
36
+
37
+ # could have the same for x=, and y=
38
+ def button= button
39
+ @button = button
40
+ refresh
41
+ end
42
+
43
+ def update x, y, button=@button
44
+ @x, @y, @button = x, y, button
45
+ refresh
46
+ end
47
+
48
+ def refresh
49
+ packet = 0.chr * 6
50
+ packet[0] = 5
51
+ packet[1] = button
52
+ packet[2, 2] = [x].pack 'n'
53
+ packet[4, 2] = [y].pack 'n'
54
+ @vnc.socket.write packet
55
+ end
56
+ end
57
+
58
+ BASE_PORT = 5900
59
+ CHALLENGE_SIZE = 16
60
+ DEFAULT_OPTIONS = {
61
+ :shared => false,
62
+ :wait => 0.1
63
+ }
64
+
65
+ keys_file = File.dirname(__FILE__) + '/../../data/keys.yaml'
66
+ KEY_MAP = YAML.load_file(keys_file).inject({}) { |h, (k, v)| h.update k.to_sym => v }
67
+ def KEY_MAP.[] key
68
+ super or raise ArgumentError.new('Invalid key name - %s' % key)
69
+ end
70
+
71
+ attr_reader :server, :display, :options, :socket, :pointer
72
+
73
+ def initialize display=':0', options={}
74
+ @server = 'localhost'
75
+ if display =~ /^(.*)(:\d+)$/
76
+ @server, display = $1, $2
77
+ end
78
+ @display = display[1..-1].to_i
79
+ @options = DEFAULT_OPTIONS.merge options
80
+ @clipboard = nil
81
+ @pointer = PointerState.new self
82
+ @mutex = Mutex.new
83
+ connect
84
+ @packet_reading_state = nil
85
+ @packet_reading_thread = Thread.new { packet_reading_thread }
86
+ end
87
+
88
+ def self.open display=':0', options={}
89
+ vnc = new display, options
90
+ if block_given?
91
+ begin
92
+ yield vnc
93
+ ensure
94
+ vnc.close
95
+ end
96
+ else
97
+ vnc
98
+ end
99
+ end
100
+
101
+ def port
102
+ BASE_PORT + @display
103
+ end
104
+
105
+ def connect
106
+ @socket = TCPSocket.open server, port
107
+ unless socket.read(12) =~ /^RFB (\d{3}.\d{3})\n$/
108
+ raise 'invalid server response'
109
+ end
110
+ @server_version = $1
111
+ socket.write "RFB 003.003\n"
112
+ data = socket.read(4)
113
+ auth = data.to_s.unpack('N')[0]
114
+ case auth
115
+ when 0, nil
116
+ raise 'connection failed'
117
+ when 1
118
+ # ok...
119
+ when 2
120
+ password = @options[:password] or raise 'Need to authenticate but no password given'
121
+ challenge = socket.read CHALLENGE_SIZE
122
+ response = Cipher::DES.encrypt password, challenge
123
+ socket.write response
124
+ ok = socket.read(4).to_s.unpack('N')[0]
125
+ raise 'Unable to authenticate - %p' % ok unless ok == 0
126
+ else
127
+ raise 'Unknown authentication scheme - %d' % auth
128
+ end
129
+
130
+ # ClientInitialisation
131
+ socket.write((options[:shared] ? 1 : 0).chr)
132
+
133
+ # ServerInitialisation
134
+ # TODO: parse this.
135
+ socket.read(20)
136
+ data = socket.read(4)
137
+ # read this many bytes in chunks of 20
138
+ size = data.to_s.unpack('N')[0]
139
+ while size > 0
140
+ len = [20, size].min
141
+ # this is the hostname, and other stuff i think...
142
+ socket.read(len)
143
+ size -= len
144
+ end
145
+ end
146
+
147
+ # this types +text+ on the server
148
+ def type text, options={}
149
+ packet = 0.chr * 8
150
+ packet[0] = 4
151
+ text.split(//).each do |char|
152
+ packet[7] = char[0]
153
+ packet[1] = 1
154
+ socket.write packet
155
+ packet[1] = 0
156
+ socket.write packet
157
+ end
158
+ wait options
159
+ end
160
+
161
+ # this takes an array of keys, and successively holds each down then lifts them up in
162
+ # reverse order.
163
+ # FIXME: should wait. can't recurse in that case.
164
+ def key_press(*args)
165
+ options = Hash === args.last ? args.pop : {}
166
+ keys = args
167
+ raise ArgumentError, 'Must have at least one key argument' if keys.empty?
168
+ begin
169
+ key_down keys.first
170
+ if keys.length == 1
171
+ yield if block_given?
172
+ else
173
+ key_press(*(keys[1..-1] + [options]))
174
+ end
175
+ ensure
176
+ key_up keys.first
177
+ end
178
+ end
179
+
180
+ def get_key_code which
181
+ if String === which
182
+ if which.length != 1
183
+ raise ArgumentError, 'can only get key_code of single character strings'
184
+ end
185
+ which[0]
186
+ else
187
+ KEY_MAP[which]
188
+ end
189
+ end
190
+ private :get_key_code
191
+
192
+ def key_down which, options={}
193
+ packet = 0.chr * 8
194
+ packet[0] = 4
195
+ key_code = get_key_code which
196
+ packet[4, 4] = [key_code].pack('N')
197
+ packet[1] = 1
198
+ socket.write packet
199
+ wait options
200
+ end
201
+
202
+ def key_up which, options={}
203
+ packet = 0.chr * 8
204
+ packet[0] = 4
205
+ key_code = get_key_code which
206
+ packet[4, 4] = [key_code].pack('N')
207
+ packet[1] = 0
208
+ socket.write packet
209
+ wait options
210
+ end
211
+
212
+ def pointer_move x, y, options={}
213
+ # options[:relative]
214
+ pointer.update x, y
215
+ wait options
216
+ end
217
+
218
+ BUTTON_MAP = {
219
+ :left => 0
220
+ }
221
+
222
+ def button_press button=:left, options={}
223
+ begin
224
+ button_down button, options
225
+ yield if block_given?
226
+ ensure
227
+ button_up button, options
228
+ end
229
+ end
230
+
231
+ def button_down which=:left, options={}
232
+ button = BUTTON_MAP[which] || which
233
+ raise ArgumentError, 'Invalid button - %p' % which unless (0..2) === button
234
+ pointer.button |= 1 << button
235
+ wait options
236
+ end
237
+
238
+ def button_up which=:left, options={}
239
+ button = BUTTON_MAP[which] || which
240
+ raise ArgumentError, 'Invalid button - %p' % which unless (0..2) === button
241
+ pointer.button &= ~(1 << button)
242
+ wait options
243
+ end
244
+
245
+ def wait options={}
246
+ sleep options[:wait] || @options[:wait]
247
+ end
248
+
249
+ def close
250
+ # destroy packet reading thread
251
+ if @packet_reading_state == :loop
252
+ @packet_reading_state = :stop
253
+ while @packet_reading_state
254
+ # do nothing
255
+ end
256
+ end
257
+ socket.close
258
+ end
259
+
260
+ def clipboard
261
+ if block_given?
262
+ @clipboard = nil
263
+ yield
264
+ 60.times do
265
+ clipboard = @mutex.synchronize { @clipboard }
266
+ return clipboard if clipboard
267
+ sleep 0.5
268
+ end
269
+ warn 'clipboard still empty after 30s'
270
+ nil
271
+ else
272
+ @mutex.synchronize { @clipboard }
273
+ end
274
+ end
275
+
276
+ private
277
+
278
+ def read_packet type
279
+ case type
280
+ when 3 # ServerCutText
281
+ socket.read 3 # discard padding bytes
282
+ len = socket.read(4).unpack('N')[0]
283
+ @mutex.synchronize { @clipboard = socket.read len }
284
+ else
285
+ raise NotImplementedError, 'unhandled server packet type - %d' % type
286
+ end
287
+ end
288
+
289
+ def packet_reading_thread
290
+ @packet_reading_state = :loop
291
+ loop do
292
+ begin
293
+ break if @packet_reading_state != :loop
294
+ next unless IO.select [socket], nil, nil, 2
295
+ type = socket.read(1)[0]
296
+ read_packet type
297
+ rescue
298
+ warn "exception in packet_reading_thread: #{$!.class}:#{$!}"
299
+ break
300
+ end
301
+ end
302
+ @packet_reading_state = nil
303
+ end
304
+ end
305
+ end
306
+
@@ -0,0 +1,6 @@
1
+ module Net
2
+ class VNC
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
6
+
@@ -0,0 +1,142 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'cipher/des'
3
+
4
+ describe 'Cipher::DES' do
5
+ DES = Cipher::DES
6
+
7
+ DATA = [
8
+ ['0xcafecafecafecafe', :encrypt, [
9
+ 11571950, 6765055, 15777490, 16705475, 7667282, 16705355, 6747478, 16709450, 7259479,
10
+ 16578410, 7323963, 16580202, 11502011, 16580218, 12520091, 12451450, 3759051, 13328317,
11
+ 3242445, 14375869, 1142229, 13851581, 5598645, 13843389, 14132645, 15940541, 14386855,
12
+ 7551935, 16356014, 7813567, 14794410, 12511175
13
+ ], [
14
+ 738924839, 154022719, 1010515743, 185740803, 490290973, 252849675, 420822813, 789982986,
15
+ 454377245, 739708714, 453263161, 1010503466, 721829689, 943394618, 791293753, 807083834,
16
+ 237974078, 353056061, 203896366, 386741565, 70726702, 370488637, 355873838, 372585277,
17
+ 890649646, 975516477, 907680814, 942093119, 1040850214, 422458175, 943337247, 455749127
18
+ ], [276147755, 314564801]],
19
+ ['0xcafecafecafecafe', :decrypt, [
20
+ 14794410, 12511175, 16356014, 7813567, 14386855, 7551935, 14132645, 15940541, 5598645,
21
+ 13843389, 1142229, 13851581, 3242445, 14375869, 3759051, 13328317, 12520091, 12451450,
22
+ 11502011, 16580218, 7323963, 16580202, 7259479, 16578410, 6747478, 16709450, 7667282,
23
+ 16705355, 15777490, 16705475, 11571950, 6765055
24
+ ], [
25
+ 943337247, 455749127, 1040850214, 422458175, 907680814, 942093119, 890649646, 975516477,
26
+ 355873838, 372585277, 70726702, 370488637, 203896366, 386741565, 237974078, 353056061,
27
+ 791293753, 807083834, 721829689, 943394618, 453263161, 1010503466, 454377245, 739708714,
28
+ 420822813, 789982986, 490290973, 252849675, 1010515743, 185740803, 738924839, 154022719
29
+ ], [3868695016, 412139341]],
30
+ ['0xdeadbeefdeadbeef', :encrypt, [
31
+ 7466991, 16631125, 16695036, 16227052, 14614126, 5292027, 15400830, 4176957, 15531887,
32
+ 7044594, 14942075, 3008831, 15597555, 15162582, 16252891, 13468671, 11426815, 16115512,
33
+ 12548989, 7945806, 9404409, 16576702, 14647293, 2457327, 14680009, 12499187, 6029295,
34
+ 10997623, 16383439, 2076626, 14630590, 13906815
35
+ ], [
36
+ 473906965, 506403861, 1060846891, 725367084, 926487615, 791546683, 977080112, 792607549,
37
+ 993860151, 254752562, 943524644, 1060838975, 993999155, 523449622, 1027552015, 1058740287,
38
+ 724516124, 624893496, 791486009, 926749454, 591347458, 926486334, 926878011, 926750511,
39
+ 926887715, 1057565491, 373238077, 1060060215, 1043793727, 521091602, 926561549, 859702079
40
+ ], [1755543026, 929731926]],
41
+ ['0xdeadbeefdeadbeef', :decrypt, [
42
+ 14630590, 13906815, 16383439, 2076626, 6029295, 10997623, 14680009, 12499187, 14647293,
43
+ 2457327, 9404409, 16576702, 12548989, 7945806, 11426815, 16115512, 16252891, 13468671,
44
+ 15597555, 15162582, 14942075, 3008831, 15531887, 7044594, 15400830, 4176957, 14614126,
45
+ 5292027, 16695036, 16227052, 7466991, 16631125
46
+ ], [
47
+ 926561549, 859702079, 1043793727, 521091602, 373238077, 1060060215, 926887715, 1057565491,
48
+ 926878011, 926750511, 591347458, 926486334, 791486009, 926749454, 724516124, 624893496,
49
+ 1027552015, 1058740287, 993999155, 523449622, 943524644, 1060838975, 993860151, 254752562,
50
+ 977080112, 792607549, 926487615, 791546683, 1060846891, 725367084, 473906965, 506403861
51
+ ], [2531611598, 527835150]]
52
+ ]
53
+
54
+ describe '(private class methods)' do
55
+ it 'can prepare keys for encryption and decryption' do
56
+ DATA.each do |hex_key, mode, stage1, stage2, expect|
57
+ key = [hex_key[2..-1]].pack('H*')
58
+ DES.send(:prepare_key_stage1, key, mode).should == stage1
59
+ DES.send(:prepare_key_stage2, stage1).should == stage2
60
+ end
61
+ end
62
+
63
+ it 'can prepare perform a DES round on a block of data' do
64
+ DATA.each do |hex_key, mode, stage1, stage2, expect|
65
+ DES.send(:desfunc, [0, 0], stage2).should == expect
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '#initialize' do
71
+ it 'can create a DES object from a key and a mode' do
72
+ hex_key, mode, stage1, stage2, expect = DATA[0]
73
+ key = [hex_key[2..-1]].pack('H*')
74
+ des = DES.new key, mode
75
+ des.key.should == key
76
+ des.mode.should == mode
77
+ des.instance_variable_get(:@buf).should == ''
78
+ des.instance_variable_get(:@keys).should == stage2
79
+ end
80
+
81
+ it 'will reject invalid modes' do
82
+ lambda { DES.new 'key', :encryptify }.should raise_error(ArgumentError)
83
+ end
84
+
85
+ it 'expands or truncates the key to 8 bytes' do
86
+ DES.new('my-really-long-key', :encrypt).key.should == 'my-reall'
87
+ DES.new('key', :encrypt).key.should == "key\000\000\000\000\000"
88
+ end
89
+ end
90
+
91
+ describe '#update' do
92
+ before :each do
93
+ hex_key, mode, stage1, stage2, @expect = DATA[0]
94
+ key = [hex_key[2..-1]].pack('H*')
95
+ @des = DES.new key, mode
96
+ end
97
+
98
+ it 'will return the data in ciphered form' do
99
+ @des.update([0, 0].pack('N2')).should == @expect.pack('N2')
100
+ end
101
+
102
+ it 'will store the residual in buffer' do
103
+ @des.update([0].pack('N')).should == ''
104
+ @des.instance_variable_get(:@buf).should == [0].pack('N')
105
+ @des.update([0].pack('N')).should == @expect.pack('N2')
106
+ @des.instance_variable_get(:@buf).should == ''
107
+ end
108
+ end
109
+
110
+ describe '#final' do
111
+ before :each do
112
+ hex_key, mode, stage1, stage2, @expect = DATA[0]
113
+ key = [hex_key[2..-1]].pack('H*')
114
+ @des = DES.new key, mode
115
+ end
116
+
117
+ it 'will flush the buffer by padding with null bytes' do
118
+ @des.final.should == ''
119
+ @des.update([0].pack('N')).should == ''
120
+ @des.final.should == @expect.pack('N2')
121
+ end
122
+ end
123
+
124
+ describe '.encrypt' do
125
+ it 'is a shortcut class method for DES encryption' do
126
+ hex_key, mode, stage1, stage2, expect = DATA[0]
127
+ key = [hex_key[2..-1]].pack('H*')
128
+ mode.should == :encrypt
129
+ DES.encrypt(key, [0].pack('N')).should == expect.pack('N2')
130
+ end
131
+ end
132
+
133
+ describe '.decrypt' do
134
+ it 'is a shortcut class method for DES decryption' do
135
+ hex_key, mode, stage1, stage2, expect = DATA[1]
136
+ key = [hex_key[2..-1]].pack('H*')
137
+ mode.should == :decrypt
138
+ DES.decrypt(key, [0].pack('N')).should == expect.pack('N2')
139
+ end
140
+ end
141
+ end
142
+
@@ -0,0 +1,136 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'net/vnc'
3
+
4
+ =begin
5
+ class SocketMock
6
+ class MockIOError < IOError
7
+ end
8
+
9
+ def initialize
10
+ # this can be used to make detailed assertions
11
+ @trace = []
12
+ @read_buf = ''
13
+ @write_buf = ''
14
+ end
15
+
16
+ def read len
17
+ @trace << [:read, len]
18
+ if @read_buf.length < len
19
+ msg = 'bad socket read sequence - read(%d) but only %d byte(s) available' % [len, @read_buf.length]
20
+ raise MockIOError, msg
21
+ end
22
+ @read_buf.slice! 0, len
23
+ end
24
+
25
+ def write data
26
+ @trace << [:write, data]
27
+ @write_buf << data
28
+ end
29
+ end
30
+
31
+ class VNCServerSocketMock < SocketMock
32
+ TICK_TIME = 0.1
33
+
34
+ def initialize(&block)
35
+ super
36
+
37
+ @pending_read = nil
38
+ obj = self
39
+ @t = Thread.new { block.call obj; @pending_read = nil }
40
+ 100.times do |i|
41
+ break if @pending_read
42
+ if i == 99
43
+ msg = 'blah'
44
+ raise MockIOError, msg
45
+ end
46
+ sleep TICK_TIME
47
+ end
48
+ end
49
+
50
+ def run
51
+ yield
52
+ 100.times do |i|
53
+ break unless @pending_read
54
+ if i == 99
55
+ msg = 'missing socket write sequence'
56
+ raise MockIOError, msg
57
+ end
58
+ sleep TICK_TIME
59
+ end
60
+ raise 'wrote to much' if @write_buf.length != 0
61
+ raise 'did not read enough' if @read_buf.length != 0
62
+ end
63
+
64
+ def read len
65
+ @trace << [:read, len]
66
+ 100.times do |i|
67
+ break if @read_buf.length >= len
68
+ if i == 99
69
+ msg = 'timeout during socket read sequence - read(%d) but only %d byte(s) available' % [len, @read_buf.length]
70
+ raise MockIOError, msg
71
+ end
72
+ sleep TICK_TIME
73
+ end
74
+ @read_buf.slice! 0, len
75
+ end
76
+
77
+ def write data
78
+ unless @read_buf.empty?
79
+ raise MockIOError, 'tried to write with non empty read buffer - (%p, %p)' % [@read_buf, data]
80
+ end
81
+ super
82
+ if !@pending_read
83
+ raise MockIOError, "wrote to socket but server is not expecting it"
84
+ end
85
+ if @write_buf.length >= @pending_read
86
+ @pending_read = @write_buf.slice!(0, @pending_read)
87
+ sleep TICK_TIME while @pending_read.is_a? String
88
+ end
89
+ end
90
+
91
+ def provide_data data
92
+ @read_buf << data
93
+ end
94
+
95
+ def expect_data len
96
+ @pending_read = len
97
+ sleep TICK_TIME while @pending_read.is_a? Fixnum
98
+ @pending_read
99
+ end
100
+ end
101
+
102
+ describe 'Net::VNC' do
103
+ VNC = Net::VNC
104
+
105
+ it 'should do something' do
106
+ =begin
107
+ socket_mock.should_receive(:read).once.ordered.with(12).and_return("RFB 003.003\n")
108
+ socket_mock.should_receive(:write).once.ordered.with(/^RFB (\d{3}.\d{3})\n$/)
109
+ socket_mock.should_receive(:read).once.ordered.with(4).and_return([1].pack('N'))
110
+ socket_mock.should_receive(:write).once.ordered.with("\000")
111
+ socket_mock.should_receive(:read).once.ordered.with(20).and_return('')
112
+ socket_mock.should_receive(:read).once.ordered.with(4).and_return([0].pack('N'))
113
+ #m = mock('my mock')
114
+ #m.should_receive(:test1).ordered.once.with('argument').and_return(1)
115
+ #m.should_receive(:test2).ordered.once.with('argument').and_return(2)
116
+ #p m.test1('argument')
117
+ #p m.test2('argument')
118
+ vnc = VNC.open('192.168.0.1:0')
119
+ #=end
120
+
121
+ server = VNCServerSocketMock.new do |s|
122
+ s.provide_data "RFB 003.003\n"
123
+ p :read => s.expect_data(12)
124
+ s.provide_data [1].pack('N')
125
+ p :read => s.expect_data(1)
126
+ s.provide_data ' ' * 20
127
+ s.provide_data [0].pack('N')
128
+ end
129
+ server.run do
130
+ TCPSocket.should_receive(:open).with('192.168.0.1', 5900).and_return(server)
131
+ vnc = VNC.open('192.168.0.1:0')
132
+ end
133
+ end
134
+ end
135
+ =end
136
+
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-vnc
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Charles Lowe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-29 00:00:00 +10:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A library which implements the client VNC protocol to control VNC servers.
17
+ email: aquasync@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - Rakefile
26
+ - README
27
+ - ChangeLog
28
+ - data/keys.yaml
29
+ - lib/cipher/des.rb
30
+ - lib/net/vnc/version.rb
31
+ - lib/net/vnc.rb
32
+ - spec/cipher_des_spec.rb
33
+ - spec/net_vnc_spec.rb
34
+ has_rdoc: true
35
+ homepage:
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --main
39
+ - README
40
+ - --title
41
+ - ruby-vnc documentation
42
+ - --tab-width
43
+ - "2"
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.2.0
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: Ruby VNC library.
65
+ test_files: []
66
+