blob: 071ce4b74f48f0ba2a40a3a9a9a261e6fba2e4a1 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
'use strict';
var testUsername = 'testUsername@gmail.com';
var testToken = 'testToken';
/** @type {(sinon.Spy|function(string):void)} */
var sendMessage_spy = function(msg) {};
/** @type {function(string):void} */
var sendMessage = function(msg) {};
/** @type {(sinon.Spy|function():void)} */
var startTls_spy = function() {};
/** @type {function():void} */
var startTls = function() {};
/** @type {(sinon.Spy|function(string, remoting.XmppStreamParser):void)} */
var onHandshakeDone_spy = function(name, parser) {};
/** @type {function(string, remoting.XmppStreamParser):void} */
var onHandshakeDone = function(name, parser) {};
/** @type {(sinon.Spy|function(remoting.Error, string):void)} */
var onError_spy = function(error, message) {};
/** @type {function(remoting.Error, string):void} */
var onError = function(error, message) {};
/** @type {remoting.XmppLoginHandler} */
var loginHandler = null;
QUnit.module('XmppLoginHandler', {
beforeEach: function() {
sendMessage_spy = sinon.spy();
sendMessage = /** @type {function(string):void} */ (sendMessage_spy);
startTls_spy = sinon.spy();
startTls = /** @type {function():void} */ (startTls_spy);
onHandshakeDone_spy = sinon.spy();
onHandshakeDone =
/** @type {function(string, remoting.XmppStreamParser):void} */
(onHandshakeDone_spy);
onError_spy = sinon.spy();
onError = /** @type {function(remoting.Error, string):void} */(onError_spy);
loginHandler = new remoting.XmppLoginHandler(
'google.com', testUsername, testToken,
remoting.TlsMode.WITHOUT_HANDSHAKE, sendMessage, startTls,
onHandshakeDone, onError);
}
});
// Executes handshake base.
function handshakeBase() {
loginHandler.start();
sinon.assert.calledWith(startTls);
startTls_spy.reset();
loginHandler.onTlsStarted();
var cookie = window.btoa("\0" + testUsername + "\0" + testToken);
sinon.assert.calledWith(
sendMessage,
'<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
'xmlns:stream="http://etherx.jabber.org/streams">' +
'<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="X-OAUTH2" ' +
'auth:service="oauth2" auth:allow-generated-jid="true" ' +
'auth:client-uses-full-bind-result="true" ' +
'auth:allow-non-google-login="true" ' +
'xmlns:auth="http://www.google.com/talk/protocol/auth">' + cookie +
'</auth>');
sendMessage_spy.reset();
loginHandler.onDataReceived(base.encodeUtf8(
'<stream:stream from="google.com" id="DCDDE5171CB2154A" version="1.0" ' +
'xmlns:stream="http://etherx.jabber.org/streams" ' +
'xmlns="jabber:client">' +
'<stream:features>' +
'<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
'<mechanism>X-OAUTH2</mechanism>' +
'<mechanism>X-GOOGLE-TOKEN</mechanism>' +
'<mechanism>PLAIN</mechanism>' +
'</mechanisms>' +
'</stream:features>'));
}
QUnit.test('should authenticate', function() {
handshakeBase();
loginHandler.onDataReceived(
base.encodeUtf8('<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>'));
sinon.assert.calledWith(
sendMessage,
'<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
'xmlns:stream="http://etherx.jabber.org/streams">' +
'<iq type="set" id="0">' +
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
'<resource>chromoting</resource>' +
'</bind>' +
'</iq>' +
'<iq type="set" id="1">' +
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
'</iq>');
sendMessage_spy.reset();
loginHandler.onDataReceived(base.encodeUtf8(
'<stream:stream from="google.com" id="104FA10576E2AA80" version="1.0" ' +
'xmlns:stream="http://etherx.jabber.org/streams" ' +
'xmlns="jabber:client">' +
'<stream:features>' +
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>' +
'<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
'</stream:features>' +
'<iq id="0" type="result">' +
'<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
'<jid>' + testUsername + '/chromoting52B4920E</jid>' +
'</bind>' +
'</iq>' +
'<iq type="result" id="1"/>'));
sinon.assert.calledWith(onHandshakeDone);
});
QUnit.test('use <starttls> handshake', function() {
loginHandler = new remoting.XmppLoginHandler(
'google.com', testUsername, testToken, remoting.TlsMode.WITH_HANDSHAKE,
sendMessage, startTls, onHandshakeDone, onError);
loginHandler.start();
sinon.assert.calledWith(
sendMessage,
'<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
'xmlns:stream="http://etherx.jabber.org/streams">' +
'<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
sendMessage_spy.reset();
loginHandler.onDataReceived(base.encodeUtf8(
'<stream:stream from="google.com" id="78A87C70559EF28A" version="1.0" ' +
'xmlns:stream="http://etherx.jabber.org/streams" ' +
'xmlns="jabber:client">' +
'<stream:features>' +
'<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">' +
'<required/>' +
'</starttls>' +
'<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
'<mechanism>X-OAUTH2</mechanism>' +
'<mechanism>X-GOOGLE-TOKEN</mechanism>' +
'</mechanisms>' +
'</stream:features>'));
loginHandler.onDataReceived(
base.encodeUtf8('<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>'));
sinon.assert.calledWith(startTls);
});
QUnit.test(
'should return AUTHENTICATION_FAILED error when failed to authenticate',
function() {
handshakeBase();
loginHandler.onDataReceived(
base.encodeUtf8('<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
'<not-authorized/></failure>'));
sinon.assert.calledWith(onError, new remoting.Error(
remoting.Error.Tag.AUTHENTICATION_FAILED));
});
QUnit.test('should return UNEXPECTED error when failed to parse stream',
function() {
handshakeBase();
loginHandler.onDataReceived(
base.encodeUtf8('BAD DATA'));
sinon.assert.calledWith(onError, remoting.Error.unexpected());
});
})();