@@ -3,9 +3,12 @@ import 'dart:convert';
3
3
import 'dart:io' ;
4
4
import 'dart:typed_data' ;
5
5
6
+ import 'package:dart_des/dart_des.dart' ;
6
7
import 'package:dart_rfb/src/client/config.dart' ;
7
8
import 'package:dart_rfb/src/client/remote_frame_buffer_client_update.dart' ;
9
+ import 'package:dart_rfb/src/constants.dart' ;
8
10
import 'package:dart_rfb/src/extensions/byte_data_extensions.dart' ;
11
+ import 'package:dart_rfb/src/extensions/int_extensions.dart' ;
9
12
import 'package:dart_rfb/src/protocol/client_init_message.dart' ;
10
13
import 'package:dart_rfb/src/protocol/frame_buffer_update_message.dart' ;
11
14
import 'package:dart_rfb/src/protocol/frame_buffer_update_request_message.dart' ;
@@ -34,6 +37,8 @@ class RemoteFrameBufferClient {
34
37
35
38
bool _readLoopRunning = false ;
36
39
40
+ Option <String > _password = none ();
41
+
37
42
/// A client that implements communication according to
38
43
/// The Remote Framebuffer Protocol, aka RFC 6143, aka VNC).
39
44
RemoteFrameBufferClient () {
@@ -78,13 +83,16 @@ class RemoteFrameBufferClient {
78
83
);
79
84
}
80
85
81
- /// Connect to [hostname] on [port] and perform the protocol handshake.
86
+ /// Connect to [hostname] on [port] and perform the protocol handshake,
87
+ /// optionally using [password] .
82
88
Future <void > connect ({
83
89
required final String hostname,
90
+ final String ? password,
84
91
final int port = 5900 ,
85
92
}) async =>
86
93
(await TaskEither <Object , void >.tryCatch (
87
94
() async {
95
+ _password = optionOf (password);
88
96
_socket = some (
89
97
await RawSocket .connect (
90
98
hostname,
@@ -147,7 +155,7 @@ class RemoteFrameBufferClient {
147
155
_readLoopRunning = true ;
148
156
while (_readLoopRunning) {
149
157
while (socket.available () < 1 ) {
150
- await Future <void >.delayed (const Duration (seconds : 1 ) );
158
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
151
159
}
152
160
final int messageType = optionOf (socket.read (1 ))
153
161
.map (
@@ -163,7 +171,9 @@ class RemoteFrameBufferClient {
163
171
switch (messageType) {
164
172
case 0 :
165
173
while (socket.available () < 1 ) {
166
- await Future <void >.delayed (const Duration (seconds: 1 ));
174
+ await Future <void >.delayed (
175
+ Constants .socketReadWaitDuration,
176
+ );
167
177
}
168
178
// read and ignore padding
169
179
optionOf (socket.read (1 )).getOrElse (
@@ -207,7 +217,9 @@ class RemoteFrameBufferClient {
207
217
break ;
208
218
case 1 : // SetColorMapEntries
209
219
while (socket.available () < 5 ) {
210
- await Future <void >.delayed (const Duration (seconds: 1 ));
220
+ await Future <void >.delayed (
221
+ Constants .socketReadWaitDuration,
222
+ );
211
223
}
212
224
final int numberOfColors = optionOf (socket.read (5 ))
213
225
.map (
@@ -219,7 +231,9 @@ class RemoteFrameBufferClient {
219
231
throw Exception ('Error reading number of colors' ),
220
232
);
221
233
while (socket.available () < numberOfColors * 6 ) {
222
- await Future <void >.delayed (const Duration (seconds: 1 ));
234
+ await Future <void >.delayed (
235
+ Constants .socketReadWaitDuration,
236
+ );
223
237
}
224
238
optionOf (socket.read (numberOfColors * 6 )).getOrElse (
225
239
() => throw Exception ('Error reading colors' ),
@@ -230,7 +244,9 @@ class RemoteFrameBufferClient {
230
244
break ;
231
245
case 3 : // ServerCutText
232
246
while (socket.available () < 7 ) {
233
- await Future <void >.delayed (const Duration (seconds: 1 ));
247
+ await Future <void >.delayed (
248
+ Constants .socketReadWaitDuration,
249
+ );
234
250
}
235
251
final int length = optionOf (socket.read (7 ))
236
252
.map (
@@ -241,7 +257,9 @@ class RemoteFrameBufferClient {
241
257
() => throw Exception ('Error reading length' ),
242
258
);
243
259
while (socket.available () < length) {
244
- await Future <void >.delayed (const Duration (seconds: 1 ));
260
+ await Future <void >.delayed (
261
+ Constants .socketReadWaitDuration,
262
+ );
245
263
}
246
264
optionOf (socket.read (length)).getOrElse (
247
265
() => throw Exception ('Error reading content' ),
@@ -271,19 +289,71 @@ class RemoteFrameBufferClient {
271
289
.andThen (() => _sendProtocolVersionMessage (socket: socket))
272
290
.andThen (() => _readSecurityHandshake (socket: socket))
273
291
.andThen (() => _sendSecurityType (socket: socket))
292
+ .andThen (() => _handleSecurityType (socket: socket))
274
293
.andThen (() => _readSecurityResultMessage (socket: socket))
275
294
.andThen (() => _sendClientInitMessage (socket: socket))
276
295
.andThen (() => _readServerInitMessage (socket: socket)),
277
296
);
278
297
298
+ TaskEither <Object , void > _handleSecurityType ({
299
+ required final RawSocket socket,
300
+ }) =>
301
+ _password.match (
302
+ () => TaskEither <Object , void >.of (null ),
303
+ (final String password) => TaskEither <Object , void >.tryCatch (
304
+ () async {
305
+ while (socket.available () < 16 ) {
306
+ await Future <void >.delayed (Constants .socketReadWaitDuration);
307
+ }
308
+ final ByteData challenge = ByteData .sublistView (
309
+ optionOf (socket.read (16 )).getOrElse (
310
+ () => throw Exception ('Error reading security challenge' ),
311
+ ),
312
+ );
313
+ _logger.info ('< Security challenge' );
314
+ final ByteData encodedAndTruncatedPassword = ByteData .sublistView (
315
+ Uint8List .fromList (ascii.encode (password).take (8 ).toList ()),
316
+ );
317
+ final ByteData key = ByteData (8 );
318
+ for (int i = 0 ; i < 8 ; i++ ) {
319
+ int byte;
320
+ if (i < encodedAndTruncatedPassword.lengthInBytes) {
321
+ byte = encodedAndTruncatedPassword.getUint8 (i);
322
+ } else {
323
+ byte = 0 ;
324
+ }
325
+ byte = byte.reverseBits ();
326
+ key.setUint8 (i, byte);
327
+ }
328
+ final ByteData response = ByteData .sublistView (
329
+ Uint8List .fromList (
330
+ DES (
331
+ key: key.asUint8List (),
332
+ mode: DESMode .ECB ,
333
+ paddingType: DESPaddingType .PKCS7 ,
334
+ ).encrypt (challenge.asUint8List ()),
335
+ ),
336
+ 0 ,
337
+ 16 ,
338
+ );
339
+ _logger.info ('> Security challenge response' );
340
+ socket.write (
341
+ response.buffer
342
+ .asUint8List (response.offsetInBytes, response.lengthInBytes),
343
+ );
344
+ },
345
+ (final Object error, final _) => error,
346
+ ),
347
+ );
348
+
279
349
TaskEither <Object , void > _readProtocolVersionMessage ({
280
350
required final RawSocket socket,
281
351
}) =>
282
352
TaskEither <Object , void >.tryCatch (
283
353
() async {
284
354
while (socket.available () <
285
355
RemoteFrameBufferProtocolVersionHandshakeMessage .length) {
286
- await Future <void >.delayed (const Duration (seconds : 1 ) );
356
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
287
357
}
288
358
final RemoteFrameBufferProtocolVersionHandshakeMessage
289
359
protocolVersionHandshakeMessage =
@@ -317,7 +387,7 @@ class RemoteFrameBufferClient {
317
387
TaskEither <Object , void >.tryCatch (
318
388
() async {
319
389
while (socket.available () < 1 ) {
320
- await Future <void >.delayed (const Duration (seconds : 1 ) );
390
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
321
391
}
322
392
final int numberOfSecurityTypes = optionOf (socket.read (1 )).getOrElse (
323
393
() => throw Exception ('Error reading number of security types' ),
@@ -329,15 +399,15 @@ class RemoteFrameBufferClient {
329
399
if (numberOfSecurityTypes == 0 ) {
330
400
// Error, next 4 bytes is reason-length, then reason-string
331
401
while (socket.available () < 4 ) {
332
- await Future <void >.delayed (const Duration (seconds : 1 ) );
402
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
333
403
}
334
404
final int reasonLength = ByteData .sublistView (
335
405
optionOf (socket.read (4 )).getOrElse (
336
406
() => throw Exception ('Error getting reason length' ),
337
407
),
338
408
).getUint32 (0 );
339
409
while (socket.available () < reasonLength) {
340
- await Future <void >.delayed (const Duration (seconds : 1 ) );
410
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
341
411
}
342
412
final String reason = optionOf (socket.read (reasonLength))
343
413
.map ((final Uint8List bytes) => ascii.decode (bytes))
@@ -347,7 +417,7 @@ class RemoteFrameBufferClient {
347
417
);
348
418
} else {
349
419
while (socket.available () < numberOfSecurityTypes) {
350
- await Future <void >.delayed (const Duration (seconds : 1 ) );
420
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
351
421
}
352
422
final RemoteFrameBufferSecurityHandshakeMessage
353
423
securityResultHandshakeMessage =
@@ -364,10 +434,21 @@ class RemoteFrameBufferClient {
364
434
),
365
435
);
366
436
_logger.log (Level .INFO , '< $securityResultHandshakeMessage ' );
367
- if (securityResultHandshakeMessage.securityTypes.notElem (
368
- const RemoteFrameBufferSecurityType .none (),
369
- )) {
370
- throw Exception ('Server does not support security type "none"' );
437
+ if (_password.isNone () &&
438
+ securityResultHandshakeMessage.securityTypes.notElem (
439
+ const RemoteFrameBufferSecurityType .none (),
440
+ )) {
441
+ throw Exception (
442
+ 'Server does not support security type "none", but not password was provided' ,
443
+ );
444
+ }
445
+ if (_password.isSome () &&
446
+ securityResultHandshakeMessage.securityTypes.notElem (
447
+ const RemoteFrameBufferSecurityType .vncAuthentication (),
448
+ )) {
449
+ throw Exception (
450
+ 'Server does not support security type "vncAuthentication"' ,
451
+ );
371
452
}
372
453
}
373
454
},
@@ -380,7 +461,7 @@ class RemoteFrameBufferClient {
380
461
TaskEither <Object , void >.tryCatch (
381
462
() async {
382
463
while (socket.available () < 4 ) {
383
- await Future <void >.delayed (const Duration (seconds : 1 ) );
464
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
384
465
}
385
466
final RemoteFrameBufferSecurityResultHandshakeMessage
386
467
securityResultHandshakeMessage =
@@ -396,7 +477,7 @@ class RemoteFrameBufferClient {
396
477
_logger.log (Level .INFO , '< $securityResultHandshakeMessage ' );
397
478
if (! securityResultHandshakeMessage.success) {
398
479
while (socket.available () < 4 ) {
399
- await Future <void >.delayed (const Duration (seconds : 1 ) );
480
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
400
481
}
401
482
final int reasonLength = optionOf (socket.read (4 ))
402
483
.map (
@@ -407,7 +488,7 @@ class RemoteFrameBufferClient {
407
488
() => throw Exception ('Error reading reason length' ),
408
489
);
409
490
while (socket.available () < reasonLength) {
410
- await Future <void >.delayed (const Duration (seconds : 1 ) );
491
+ await Future <void >.delayed (Constants .socketReadWaitDuration );
411
492
}
412
493
final String reason = optionOf (socket.read (reasonLength))
413
494
.map ((final Uint8List bytes) => ascii.decode (bytes))
@@ -474,13 +555,16 @@ class RemoteFrameBufferClient {
474
555
}) =>
475
556
TaskEither <Object , void >.tryCatch (
476
557
() async {
558
+ final RemoteFrameBufferSecurityType securityType = _password.match (
559
+ () => const RemoteFrameBufferSecurityType .none (),
560
+ (final _) =>
561
+ const RemoteFrameBufferSecurityType .vncAuthentication (),
562
+ );
477
563
_logger.log (
478
564
Level .INFO ,
479
- '> ${const RemoteFrameBufferSecurityType .none ()}' ,
480
- );
481
- socket.write (
482
- const RemoteFrameBufferSecurityType .none ().toBytes ().asUint8List (),
565
+ '> $securityType ' ,
483
566
);
567
+ socket.write (securityType.toBytes ().asUint8List ());
484
568
},
485
569
(final Object error, final _) => error,
486
570
);
0 commit comments