Allow other credentials than just password
Makes the XVP authentication mechanism more general.
This commit is contained in:
parent
233c8b6a53
commit
430f00d6fe
14
app/ui.js
14
app/ui.js
|
@ -206,7 +206,7 @@ var UI = {
|
||||||
'onNotification': UI.notification,
|
'onNotification': UI.notification,
|
||||||
'onUpdateState': UI.updateState,
|
'onUpdateState': UI.updateState,
|
||||||
'onDisconnected': UI.disconnectFinished,
|
'onDisconnected': UI.disconnectFinished,
|
||||||
'onPasswordRequired': UI.passwordRequired,
|
'onCredentialsRequired': UI.credentials,
|
||||||
'onXvpInit': UI.updateXvpButton,
|
'onXvpInit': UI.updateXvpButton,
|
||||||
'onClipboard': UI.clipboardReceive,
|
'onClipboard': UI.clipboardReceive,
|
||||||
'onBell': UI.bell,
|
'onBell': UI.bell,
|
||||||
|
@ -1067,7 +1067,7 @@ var UI = {
|
||||||
UI.updateLocalCursor();
|
UI.updateLocalCursor();
|
||||||
UI.updateViewOnly();
|
UI.updateViewOnly();
|
||||||
|
|
||||||
UI.rfb.connect(host, port, password, path);
|
UI.rfb.connect(host, port, { password: password }, path);
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnect: function() {
|
disconnect: function() {
|
||||||
|
@ -1127,8 +1127,8 @@ var UI = {
|
||||||
* PASSWORD
|
* PASSWORD
|
||||||
* ------v------*/
|
* ------v------*/
|
||||||
|
|
||||||
passwordRequired: function(rfb, msg) {
|
credentials: function(rfb, types) {
|
||||||
|
// FIXME: handle more types
|
||||||
document.getElementById('noVNC_password_dlg')
|
document.getElementById('noVNC_password_dlg')
|
||||||
.classList.add('noVNC_open');
|
.classList.add('noVNC_open');
|
||||||
|
|
||||||
|
@ -1136,9 +1136,7 @@ var UI = {
|
||||||
document.getElementById('noVNC_password_input').focus();
|
document.getElementById('noVNC_password_input').focus();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
if (typeof msg === 'undefined') {
|
var msg = _("Password is required");
|
||||||
msg = _("Password is required");
|
|
||||||
}
|
|
||||||
Log.Warn(msg);
|
Log.Warn(msg);
|
||||||
UI.showStatus(msg, "warning");
|
UI.showStatus(msg, "warning");
|
||||||
},
|
},
|
||||||
|
@ -1148,7 +1146,7 @@ var UI = {
|
||||||
var password = inputElem.value;
|
var password = inputElem.value;
|
||||||
// Clear the input after reading the password
|
// Clear the input after reading the password
|
||||||
inputElem.value = "";
|
inputElem.value = "";
|
||||||
UI.rfb.sendPassword(password);
|
UI.rfb.sendCredentials({ password: password });
|
||||||
UI.reconnect_password = password;
|
UI.reconnect_password = password;
|
||||||
document.getElementById('noVNC_password_dlg')
|
document.getElementById('noVNC_password_dlg')
|
||||||
.classList.remove('noVNC_open');
|
.classList.remove('noVNC_open');
|
||||||
|
|
41
core/rfb.js
41
core/rfb.js
|
@ -36,7 +36,7 @@ export default function RFB(defaults) {
|
||||||
|
|
||||||
this._rfb_host = '';
|
this._rfb_host = '';
|
||||||
this._rfb_port = 5900;
|
this._rfb_port = 5900;
|
||||||
this._rfb_password = '';
|
this._rfb_credentials = {};
|
||||||
this._rfb_path = '';
|
this._rfb_path = '';
|
||||||
|
|
||||||
this._rfb_connection_state = '';
|
this._rfb_connection_state = '';
|
||||||
|
@ -124,7 +124,6 @@ export default function RFB(defaults) {
|
||||||
'local_cursor': false, // Request locally rendered cursor
|
'local_cursor': false, // Request locally rendered cursor
|
||||||
'shared': true, // Request shared mode
|
'shared': true, // Request shared mode
|
||||||
'view_only': false, // Disable client mouse/keyboard
|
'view_only': false, // Disable client mouse/keyboard
|
||||||
'xvp_password_sep': '@', // Separator for XVP password fields
|
|
||||||
'disconnectTimeout': 3, // Time (s) to wait for disconnection
|
'disconnectTimeout': 3, // Time (s) to wait for disconnection
|
||||||
'wsProtocols': ['binary'], // Protocols to use in the WebSocket connection
|
'wsProtocols': ['binary'], // Protocols to use in the WebSocket connection
|
||||||
'repeaterID': '', // [UltraVNC] RepeaterID to connect to
|
'repeaterID': '', // [UltraVNC] RepeaterID to connect to
|
||||||
|
@ -134,7 +133,7 @@ export default function RFB(defaults) {
|
||||||
'onUpdateState': function () { }, // onUpdateState(rfb, state, oldstate): connection state change
|
'onUpdateState': function () { }, // onUpdateState(rfb, state, oldstate): connection state change
|
||||||
'onNotification': function () { }, // onNotification(rfb, msg, level, options): notification for UI
|
'onNotification': function () { }, // onNotification(rfb, msg, level, options): notification for UI
|
||||||
'onDisconnected': function () { }, // onDisconnected(rfb, reason): disconnection finished
|
'onDisconnected': function () { }, // onDisconnected(rfb, reason): disconnection finished
|
||||||
'onPasswordRequired': function () { }, // onPasswordRequired(rfb, msg): VNC password is required
|
'onCredentialsRequired': function () { }, // onCredentialsRequired(rfb, types): VNC credentials are required
|
||||||
'onClipboard': function () { }, // onClipboard(rfb, text): RFB clipboard contents received
|
'onClipboard': function () { }, // onClipboard(rfb, text): RFB clipboard contents received
|
||||||
'onBell': function () { }, // onBell(rfb): RFB Bell message received
|
'onBell': function () { }, // onBell(rfb): RFB Bell message received
|
||||||
'onFBUReceive': function () { }, // onFBUReceive(rfb, rect): RFB FBU rect received but not yet processed
|
'onFBUReceive': function () { }, // onFBUReceive(rfb, rect): RFB FBU rect received but not yet processed
|
||||||
|
@ -241,10 +240,10 @@ export default function RFB(defaults) {
|
||||||
|
|
||||||
RFB.prototype = {
|
RFB.prototype = {
|
||||||
// Public methods
|
// Public methods
|
||||||
connect: function (host, port, password, path) {
|
connect: function (host, port, creds, path) {
|
||||||
this._rfb_host = host;
|
this._rfb_host = host;
|
||||||
this._rfb_port = port;
|
this._rfb_port = port;
|
||||||
this._rfb_password = (password !== undefined) ? password : "";
|
this._rfb_credentials = (creds !== undefined) ? creds : {};
|
||||||
this._rfb_path = (path !== undefined) ? path : "";
|
this._rfb_path = (path !== undefined) ? path : "";
|
||||||
|
|
||||||
if (!this._rfb_host) {
|
if (!this._rfb_host) {
|
||||||
|
@ -264,8 +263,8 @@ RFB.prototype = {
|
||||||
this._sock.off('open');
|
this._sock.off('open');
|
||||||
},
|
},
|
||||||
|
|
||||||
sendPassword: function (passwd) {
|
sendCredentials: function (creds) {
|
||||||
this._rfb_password = passwd;
|
this._rfb_credentials = creds;
|
||||||
setTimeout(this._init_msg.bind(this), 0);
|
setTimeout(this._init_msg.bind(this), 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -848,21 +847,18 @@ RFB.prototype = {
|
||||||
|
|
||||||
// authentication
|
// authentication
|
||||||
_negotiate_xvp_auth: function () {
|
_negotiate_xvp_auth: function () {
|
||||||
var xvp_sep = this._xvp_password_sep;
|
if (!this._rfb_credentials.username ||
|
||||||
var xvp_auth = this._rfb_password.split(xvp_sep);
|
!this._rfb_credentials.password ||
|
||||||
if (xvp_auth.length < 3) {
|
!this._rfb_credentials.target) {
|
||||||
var msg = 'XVP credentials required (user' + xvp_sep +
|
this._onCredentialsRequired(this, ["username", "password", "target"]);
|
||||||
'target' + xvp_sep + 'password) -- got only ' + this._rfb_password;
|
|
||||||
this._onPasswordRequired(this, msg);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xvp_auth_str = String.fromCharCode(xvp_auth[0].length) +
|
var xvp_auth_str = String.fromCharCode(this._rfb_credentials.username.length) +
|
||||||
String.fromCharCode(xvp_auth[1].length) +
|
String.fromCharCode(this._rfb_credentials.target.length) +
|
||||||
xvp_auth[0] +
|
this._rfb_credentials.username +
|
||||||
xvp_auth[1];
|
this._rfb_credentials.target;
|
||||||
this._sock.send_string(xvp_auth_str);
|
this._sock.send_string(xvp_auth_str);
|
||||||
this._rfb_password = xvp_auth.slice(2).join(xvp_sep);
|
|
||||||
this._rfb_auth_scheme = 2;
|
this._rfb_auth_scheme = 2;
|
||||||
return this._negotiate_authentication();
|
return this._negotiate_authentication();
|
||||||
},
|
},
|
||||||
|
@ -870,14 +866,14 @@ RFB.prototype = {
|
||||||
_negotiate_std_vnc_auth: function () {
|
_negotiate_std_vnc_auth: function () {
|
||||||
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
if (this._sock.rQwait("auth challenge", 16)) { return false; }
|
||||||
|
|
||||||
if (this._rfb_password.length === 0) {
|
if (!this._rfb_credentials.password) {
|
||||||
this._onPasswordRequired(this);
|
this._onCredentialsRequired(this, ["password"]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(directxman12): make genDES not require an Array
|
// TODO(directxman12): make genDES not require an Array
|
||||||
var challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
|
var challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
|
||||||
var response = RFB.genDES(this._rfb_password, challenge);
|
var response = RFB.genDES(this._rfb_credentials.password, challenge);
|
||||||
this._sock.send(response);
|
this._sock.send(response);
|
||||||
this._rfb_init_state = "SecurityResult";
|
this._rfb_init_state = "SecurityResult";
|
||||||
return true;
|
return true;
|
||||||
|
@ -1496,7 +1492,6 @@ make_properties(RFB, [
|
||||||
['touchButton', 'rw', 'int'], // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
['touchButton', 'rw', 'int'], // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
||||||
['scale', 'rw', 'float'], // Display area scale factor
|
['scale', 'rw', 'float'], // Display area scale factor
|
||||||
['viewport', 'rw', 'bool'], // Use viewport clipping
|
['viewport', 'rw', 'bool'], // Use viewport clipping
|
||||||
['xvp_password_sep', 'rw', 'str'], // Separator for XVP password fields
|
|
||||||
['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection
|
['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection
|
||||||
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
|
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
|
||||||
['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to
|
['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to
|
||||||
|
@ -1506,7 +1501,7 @@ make_properties(RFB, [
|
||||||
['onUpdateState', 'rw', 'func'], // onUpdateState(rfb, state, oldstate): connection state change
|
['onUpdateState', 'rw', 'func'], // onUpdateState(rfb, state, oldstate): connection state change
|
||||||
['onNotification', 'rw', 'func'], // onNotification(rfb, msg, level, options): notification for the UI
|
['onNotification', 'rw', 'func'], // onNotification(rfb, msg, level, options): notification for the UI
|
||||||
['onDisconnected', 'rw', 'func'], // onDisconnected(rfb, reason): disconnection finished
|
['onDisconnected', 'rw', 'func'], // onDisconnected(rfb, reason): disconnection finished
|
||||||
['onPasswordRequired', 'rw', 'func'], // onPasswordRequired(rfb, msg): VNC password is required
|
['onCredentialsRequired', 'rw', 'func'], // onCredentialsRequired(rfb, types): VNC credentials are required
|
||||||
['onClipboard', 'rw', 'func'], // onClipboard(rfb, text): RFB clipboard contents received
|
['onClipboard', 'rw', 'func'], // onClipboard(rfb, text): RFB clipboard contents received
|
||||||
['onBell', 'rw', 'func'], // onBell(rfb): RFB Bell message received
|
['onBell', 'rw', 'func'], // onBell(rfb): RFB Bell message received
|
||||||
['onFBUReceive', 'rw', 'func'], // onFBUReceive(rfb, fbu): RFB FBU received but not yet processed
|
['onFBUReceive', 'rw', 'func'], // onFBUReceive(rfb, fbu): RFB FBU received but not yet processed
|
||||||
|
|
73
docs/API.md
73
docs/API.md
|
@ -37,7 +37,6 @@ attribute mode is one of the following:
|
||||||
| touchButton | int | RW | 1 | Button mask (1, 2, 4) for which click to send on touch devices. 0 means ignore clicks.
|
| touchButton | int | RW | 1 | Button mask (1, 2, 4) for which click to send on touch devices. 0 means ignore clicks.
|
||||||
| scale | float | RW | 1.0 | Display area scale factor
|
| scale | float | RW | 1.0 | Display area scale factor
|
||||||
| viewport | bool | RW | false | Use viewport clipping
|
| viewport | bool | RW | false | Use viewport clipping
|
||||||
| xvp_password_sep | str | RW | '@' | Separator for XVP password fields
|
|
||||||
| disconnectTimeout | int | RW | 3 | Time (in seconds) to wait for disconnection
|
| disconnectTimeout | int | RW | 3 | Time (in seconds) to wait for disconnection
|
||||||
| wsProtocols | arr | RW | ['binary'] | Protocols to use in the WebSocket connection
|
| wsProtocols | arr | RW | ['binary'] | Protocols to use in the WebSocket connection
|
||||||
| repeaterID | str | RW | '' | UltraVNC RepeaterID to connect to
|
| repeaterID | str | RW | '' | UltraVNC RepeaterID to connect to
|
||||||
|
@ -50,22 +49,22 @@ In addition to the getter and setter methods to modify configuration
|
||||||
attributes, the RFB object has other methods that are available in the
|
attributes, the RFB object has other methods that are available in the
|
||||||
object instance.
|
object instance.
|
||||||
|
|
||||||
| name | parameters | description
|
| name | parameters | description
|
||||||
| ------------------ | ------------------------------ | ------------
|
| ------------------ | ------------------------------- | ------------
|
||||||
| connect | (host, port, password, path) | Connect to the given host:port/path. Optional password and path.
|
| connect | (host, port, credentials, path) | Connect to the given host:port/path. Optional credentials and path.
|
||||||
| disconnect | () | Disconnect
|
| disconnect | () | Disconnect
|
||||||
| sendPassword | (passwd) | Send password after onPasswordRequired callback
|
| sendCredentials | (credentials) | Send credentials after onCredentialsRequired callback
|
||||||
| sendCtrlAltDel | () | Send Ctrl-Alt-Del key sequence
|
| sendCtrlAltDel | () | Send Ctrl-Alt-Del key sequence
|
||||||
| xvpOp | (ver, op) | Send a XVP operation (2=shutdown, 3=reboot, 4=reset)
|
| xvpOp | (ver, op) | Send a XVP operation (2=shutdown, 3=reboot, 4=reset)
|
||||||
| xvpShutdown | () | Send XVP shutdown.
|
| xvpShutdown | () | Send XVP shutdown.
|
||||||
| xvpReboot | () | Send XVP reboot.
|
| xvpReboot | () | Send XVP reboot.
|
||||||
| xvpReset | () | Send XVP reset.
|
| xvpReset | () | Send XVP reset.
|
||||||
| sendKey | (keysym, code, down) | Send a key press event. If down not specified, send a down and up event.
|
| sendKey | (keysym, code, down) | Send a key press event. If down not specified, send a down and up event.
|
||||||
| clipboardPasteFrom | (text) | Send a clipboard paste event
|
| clipboardPasteFrom | (text) | Send a clipboard paste event
|
||||||
| autoscale | (width, height, downscaleOnly) | Scale the display
|
| autoscale | (width, height, downscaleOnly) | Scale the display
|
||||||
| clippingDisplay | () | Check if the remote display is larger than the client display
|
| clippingDisplay | () | Check if the remote display is larger than the client display
|
||||||
| requestDesktopSize | (width, height) | Send a request to change the remote desktop size.
|
| requestDesktopSize | (width, height) | Send a request to change the remote desktop size.
|
||||||
| viewportChangeSize | (width, height) | Change size of the viewport
|
| viewportChangeSize | (width, height) | Change size of the viewport
|
||||||
|
|
||||||
|
|
||||||
## 3 Callbacks
|
## 3 Callbacks
|
||||||
|
@ -73,19 +72,19 @@ object instance.
|
||||||
The RFB object has certain events that can be hooked with callback
|
The RFB object has certain events that can be hooked with callback
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
| name | parameters | description
|
| name | parameters | description
|
||||||
| ------------------ | -------------------------- | ------------
|
| --------------------- | -------------------------- | ------------
|
||||||
| onUpdateState | (rfb, state, oldstate) | Connection state change (see details below)
|
| onUpdateState | (rfb, state, oldstate) | Connection state change (see details below)
|
||||||
| onNotification | (rfb, msg, level, options) | Notification for the UI (optional options)
|
| onNotification | (rfb, msg, level, options) | Notification for the UI (optional options)
|
||||||
| onDisconnected | (rfb, reason) | Disconnection finished with an optional reason. No reason specified means normal disconnect.
|
| onDisconnected | (rfb, reason) | Disconnection finished with an optional reason. No reason specified means normal disconnect.
|
||||||
| onPasswordRequired | (rfb, msg) | VNC password is required (use sendPassword), optionally comes with a message.
|
| onCredentialsRequired | (rfb, types) | VNC credentials are required (use sendCredentials)
|
||||||
| onClipboard | (rfb, text) | RFB clipboard contents received
|
| onClipboard | (rfb, text) | RFB clipboard contents received
|
||||||
| onBell | (rfb) | RFB Bell message received
|
| onBell | (rfb) | RFB Bell message received
|
||||||
| onFBUReceive | (rfb, fbu) | RFB FBU received but not yet processed (see details below)
|
| onFBUReceive | (rfb, fbu) | RFB FBU received but not yet processed (see details below)
|
||||||
| onFBUComplete | (rfb, fbu) | RFB FBU received and processed (see details below)
|
| onFBUComplete | (rfb, fbu) | RFB FBU received and processed (see details below)
|
||||||
| onFBResize | (rfb, width, height) | Frame buffer (remote desktop) size changed
|
| onFBResize | (rfb, width, height) | Frame buffer (remote desktop) size changed
|
||||||
| onDesktopName | (rfb, name) | VNC desktop name recieved
|
| onDesktopName | (rfb, name) | VNC desktop name recieved
|
||||||
| onXvpInit | (version) | XVP extensions active for this connection.
|
| onXvpInit | (version) | XVP extensions active for this connection.
|
||||||
|
|
||||||
|
|
||||||
__RFB onUpdateState callback details__
|
__RFB onUpdateState callback details__
|
||||||
|
@ -103,6 +102,20 @@ created for new connections.
|
||||||
| disconnecting | starting to disconnect
|
| disconnecting | starting to disconnect
|
||||||
| disconnected | disconnected - permanent end-state for this RFB object
|
| disconnected | disconnected - permanent end-state for this RFB object
|
||||||
|
|
||||||
|
__RFB onCredentialsRequired callback details__
|
||||||
|
|
||||||
|
The onCredentialsRequired callback is called when the server requests more
|
||||||
|
credentials than was specified to connect(). The types argument is a list
|
||||||
|
of all the credentials that are required. Currently the following are
|
||||||
|
defined:
|
||||||
|
|
||||||
|
| name | description
|
||||||
|
| -------- | ------------
|
||||||
|
| username | User that authenticates
|
||||||
|
| password | Password for user
|
||||||
|
| target | String specifying target machine or session
|
||||||
|
|
||||||
|
|
||||||
__RFB onFBUReceive and on FBUComplete callback details__
|
__RFB onFBUReceive and on FBUComplete callback details__
|
||||||
|
|
||||||
The onFBUReceive callback is invoked when a frame buffer update
|
The onFBUReceive callback is invoked when a frame buffer update
|
||||||
|
|
|
@ -104,10 +104,10 @@ RecordingPlayer.prototype = {
|
||||||
this._rfb._sock.close = function () {};
|
this._rfb._sock.close = function () {};
|
||||||
this._rfb._sock.flush = function () {};
|
this._rfb._sock.flush = function () {};
|
||||||
this._rfb._checkEvents = function () {};
|
this._rfb._checkEvents = function () {};
|
||||||
this._rfb.connect = function (host, port, password, path) {
|
this._rfb.connect = function (host, port, credentials, path) {
|
||||||
this._rfb_host = host;
|
this._rfb_host = host;
|
||||||
this._rfb_port = port;
|
this._rfb_port = port;
|
||||||
this._rfb_password = (password !== undefined) ? password : "";
|
this._rfb_credentials = {};
|
||||||
this._rfb_path = (path !== undefined) ? path : "";
|
this._rfb_path = (path !== undefined) ? path : "";
|
||||||
this._sock.init('binary', 'ws');
|
this._sock.init('binary', 'ws');
|
||||||
this._rfb_connection_state = 'connecting';
|
this._rfb_connection_state = 'connecting';
|
||||||
|
|
|
@ -116,18 +116,18 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#sendPassword', function () {
|
describe('#sendCredentials', function () {
|
||||||
beforeEach(function () { this.clock = sinon.useFakeTimers(); });
|
beforeEach(function () { this.clock = sinon.useFakeTimers(); });
|
||||||
afterEach(function () { this.clock.restore(); });
|
afterEach(function () { this.clock.restore(); });
|
||||||
|
|
||||||
it('should set the rfb password properly"', function () {
|
it('should set the rfb credentials properly"', function () {
|
||||||
client.sendPassword('pass');
|
client.sendCredentials({ password: 'pass' });
|
||||||
expect(client._rfb_password).to.equal('pass');
|
expect(client._rfb_credentials).to.deep.equal({ password: 'pass' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call init_msg "soon"', function () {
|
it('should call init_msg "soon"', function () {
|
||||||
client._init_msg = sinon.spy();
|
client._init_msg = sinon.spy();
|
||||||
client.sendPassword('pass');
|
client.sendCredentials({ password: 'pass' });
|
||||||
this.clock.tick(5);
|
this.clock.tick(5);
|
||||||
expect(client._init_msg).to.have.been.calledOnce;
|
expect(client._init_msg).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
@ -836,21 +836,22 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
client._rfb_version = 3.8;
|
client._rfb_version = 3.8;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the passwordRequired callback if missing a password', function () {
|
it('should call the onCredentialsRequired callback if missing a password', function () {
|
||||||
client.set_onPasswordRequired(sinon.spy());
|
client.set_onCredentialsRequired(sinon.spy());
|
||||||
send_security(2, client);
|
send_security(2, client);
|
||||||
|
|
||||||
var challenge = [];
|
var challenge = [];
|
||||||
for (var i = 0; i < 16; i++) { challenge[i] = i; }
|
for (var i = 0; i < 16; i++) { challenge[i] = i; }
|
||||||
client._sock._websocket._receive_data(new Uint8Array(challenge));
|
client._sock._websocket._receive_data(new Uint8Array(challenge));
|
||||||
|
|
||||||
var spy = client.get_onPasswordRequired();
|
var spy = client.get_onCredentialsRequired();
|
||||||
expect(client._rfb_password.length).to.equal(0);
|
expect(client._rfb_credentials).to.be.empty;
|
||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
|
expect(spy.args[0][1]).to.have.members(["password"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should encrypt the password with DES and then send it back', function () {
|
it('should encrypt the password with DES and then send it back', function () {
|
||||||
client._rfb_password = 'passwd';
|
client._rfb_credentials = { password: 'passwd' };
|
||||||
send_security(2, client);
|
send_security(2, client);
|
||||||
client._sock._websocket._get_sent_data(); // skip the choice of auth reply
|
client._sock._websocket._get_sent_data(); // skip the choice of auth reply
|
||||||
|
|
||||||
|
@ -863,7 +864,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transition to SecurityResult immediately after sending the password', function () {
|
it('should transition to SecurityResult immediately after sending the password', function () {
|
||||||
client._rfb_password = 'passwd';
|
client._rfb_credentials = { password: 'passwd' };
|
||||||
send_security(2, client);
|
send_security(2, client);
|
||||||
|
|
||||||
var challenge = [];
|
var challenge = [];
|
||||||
|
@ -886,41 +887,44 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fall through to standard VNC authentication upon completion', function () {
|
it('should fall through to standard VNC authentication upon completion', function () {
|
||||||
client.set_xvp_password_sep('#');
|
client._rfb_credentials = { username: 'user',
|
||||||
client._rfb_password = 'user#target#password';
|
target: 'target',
|
||||||
|
password: 'password' };
|
||||||
client._negotiate_std_vnc_auth = sinon.spy();
|
client._negotiate_std_vnc_auth = sinon.spy();
|
||||||
send_security(22, client);
|
send_security(22, client);
|
||||||
expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
|
expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the passwordRequired callback if the password is missing', function() {
|
it('should call the onCredentialsRequired callback if all credentials are missing', function() {
|
||||||
client.set_onPasswordRequired(sinon.spy());
|
client.set_onCredentialsRequired(sinon.spy());
|
||||||
client._rfb_password = '';
|
client._rfb_credentials = {};
|
||||||
send_security(22, client);
|
send_security(22, client);
|
||||||
|
|
||||||
var spy = client.get_onPasswordRequired();
|
var spy = client.get_onCredentialsRequired();
|
||||||
expect(client._rfb_password.length).to.equal(0);
|
expect(client._rfb_credentials).to.be.empty;
|
||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
|
expect(spy.args[0][1]).to.have.members(["username", "password", "target"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the passwordRequired callback if the password is improperly formatted', function() {
|
it('should call the onCredentialsRequired callback if some credentials are missing', function() {
|
||||||
client.set_onPasswordRequired(sinon.spy());
|
client.set_onCredentialsRequired(sinon.spy());
|
||||||
client._rfb_password = 'user@target';
|
client._rfb_credentials = { username: 'user',
|
||||||
|
target: 'target' };
|
||||||
send_security(22, client);
|
send_security(22, client);
|
||||||
|
|
||||||
var spy = client.get_onPasswordRequired();
|
var spy = client.get_onCredentialsRequired();
|
||||||
expect(spy).to.have.been.calledOnce;
|
expect(spy).to.have.been.calledOnce;
|
||||||
|
expect(spy.args[0][1]).to.have.members(["username", "password", "target"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should split the password, send the first two parts, and pass on the last part', function () {
|
it('should send user and target separately', function () {
|
||||||
client.set_xvp_password_sep('#');
|
client._rfb_credentials = { username: 'user',
|
||||||
client._rfb_password = 'user#target#password';
|
target: 'target',
|
||||||
|
password: 'password' };
|
||||||
client._negotiate_std_vnc_auth = sinon.spy();
|
client._negotiate_std_vnc_auth = sinon.spy();
|
||||||
|
|
||||||
send_security(22, client);
|
send_security(22, client);
|
||||||
|
|
||||||
expect(client._rfb_password).to.equal('password');
|
|
||||||
|
|
||||||
var expected = [22, 4, 6]; // auth selection, len user, len target
|
var expected = [22, 4, 6]; // auth selection, len user, len target
|
||||||
for (var i = 0; i < 10; i++) { expected[i+3] = 'usertarget'.charCodeAt(i); }
|
for (var i = 0; i < 10; i++) { expected[i+3] = 'usertarget'.charCodeAt(i); }
|
||||||
|
|
||||||
|
|
|
@ -99,10 +99,7 @@
|
||||||
function updateDesktopName(rfb, name) {
|
function updateDesktopName(rfb, name) {
|
||||||
desktopName = name;
|
desktopName = name;
|
||||||
}
|
}
|
||||||
function passwordRequired(rfb, msg) {
|
function credentials(rfb, types) {
|
||||||
if (typeof msg === 'undefined') {
|
|
||||||
msg = 'Password Required: ';
|
|
||||||
}
|
|
||||||
var html;
|
var html;
|
||||||
|
|
||||||
var form = document.createElement('form');
|
var form = document.createElement('form');
|
||||||
|
@ -115,10 +112,10 @@
|
||||||
document.getElementById('noVNC_status_bar').setAttribute("class", "noVNC_status_warn");
|
document.getElementById('noVNC_status_bar').setAttribute("class", "noVNC_status_warn");
|
||||||
document.getElementById('noVNC_status').innerHTML = '';
|
document.getElementById('noVNC_status').innerHTML = '';
|
||||||
document.getElementById('noVNC_status').appendChild(form);
|
document.getElementById('noVNC_status').appendChild(form);
|
||||||
document.getElementById('noVNC_status').querySelector('label').textContent = msg;
|
document.getElementById('noVNC_status').querySelector('label').textContent = 'Password Required: ';
|
||||||
}
|
}
|
||||||
function setPassword() {
|
function setPassword() {
|
||||||
rfb.sendPassword(document.getElementById('password_input').value);
|
rfb.sendCredentials({ password: document.getElementById('password_input').value });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function sendCtrlAltDel() {
|
function sendCtrlAltDel() {
|
||||||
|
@ -266,7 +263,7 @@
|
||||||
'onUpdateState': updateState,
|
'onUpdateState': updateState,
|
||||||
'onDisconnected': disconnected,
|
'onDisconnected': disconnected,
|
||||||
'onXvpInit': xvpInit,
|
'onXvpInit': xvpInit,
|
||||||
'onPasswordRequired': passwordRequired,
|
'onCredentialsRequired': credentials,
|
||||||
'onFBUComplete': FBUComplete,
|
'onFBUComplete': FBUComplete,
|
||||||
'onDesktopName': updateDesktopName});
|
'onDesktopName': updateDesktopName});
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
|
@ -274,7 +271,7 @@
|
||||||
return; // don't continue trying to connect
|
return; // don't continue trying to connect
|
||||||
}
|
}
|
||||||
|
|
||||||
rfb.connect(host, port, password, path);
|
rfb.connect(host, port, { password: password }, path);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
Loading…
Reference in New Issue