Commit 9849daac authored by JC Brand's avatar JC Brand

Merge branch 'master' into 0.8

Conflicts:
	bower.json
	converse.js
	docs/CHANGES.rst
	spec/chatbox.js
	tests/utils.js
	tests_main.js
parents 34fa0588 8001444a
{
"name": "converse",
"version": "0.7.3",
"version": "0.7.4",
"devDependencies": {
"jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x",
"otr": "0.2.7",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -43,7 +43,8 @@
if (list) {
for (i=0; i<list.length; i++) {
var prot = list[i].indexOf('http://') === 0 || list[i].indexOf('https://') === 0 ? '' : 'http://';
x = x.replace(list[i], "<a target='_blank' href='" + prot + list[i] + "'>"+ list[i] + "</a>" );
var escaped_url = encodeURI(decodeURI(list[i])).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
x = x.replace(list[i], "<a target='_blank' href='" + prot + escaped_url + "'>"+ list[i] + "</a>" );
}
}
$(obj).html(x);
......@@ -942,15 +943,16 @@
msg_date = msg_dict.time ? converse.parseISO8601(msg_dict.time) : new Date(),
text = msg_dict.message,
match = text.match(/^\/(.*?)(?: (.*))?$/),
fullname = msg_dict.fullname || this.model.get('fullname'),
template, username;
if ((match) && (match[1] === 'me')) {
text = text.replace(/^\/me/, '');
template = converse.templates.action_template;
username = msg_dict.fullname;
username = fullname;
} else {
template = converse.templates.message;
username = msg_dict.sender === 'me' && __('me') || msg_dict.fullname || this.model.get('fullname');
username = msg_dict.sender === 'me' && __('me') || fullname;
}
$el.find('div.chat-event').remove();
var message = template({
......
......@@ -7,6 +7,16 @@ Changelog
* Chat boxes and rooms can now be resized vertically. [jcbrand]
* Chat boxes and rooms can be minimized. [jcbrand]
0.7.4 (2014-03-05)
------------------
.. note:: This release contains an important security fix.
Thanks to Renaud Dubourguais from `Synacktiv http://synacktiv.com`_ for reporting the vulnerability.
* #125 Bugfix: crypto dependencies loaded in wrong order [jcbrand]
* Bugfix: action messages (i.e. /me) didn't work in OTR mode. [jcbrand]
* Security fix: Ensure that message URLs are properly encoded. [jcbrand]
0.7.3 (2014-02-23)
------------------
......@@ -22,11 +32,12 @@ Changelog
------------------
.. note:: This release contains an important security fix.
Thanks to hejsan for reporting the vulnerability.
* #48 Add event emitter support and emit events. [jcbrand]
* #97 Wrong number of online contacts shown with config option ``show_only_online_users``. [jcbrand]
* #100 Make the fetching of vCards optional (enabled by default). [jcbrand]
* Sanitize message text to avoid Javascript injection attacks. Thanks to hejsan for reporting. [jcbrand]
* Sanitize message text to avoid Javascript injection attacks. [jcbrand]
0.7.1 (2013-11-17)
------------------
......
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 738ca7b60aed811ee1668ad08d26eabb
config: 0660e50cf30718622673fcf0e779dfd4
tags: fbb0d17656682115ca4d033fb2f83ba1
......@@ -9,7 +9,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &mdash; Converse.js 0.7.3 documentation</title>
<title>Index &mdash; Converse.js 0.7.4 documentation</title>
<link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
......@@ -17,7 +17,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7.3',
VERSION: '0.7.4',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
......@@ -26,7 +26,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Converse.js 0.7.3 documentation" href="index.html" />
<link rel="top" title="Converse.js 0.7.4 documentation" href="index.html" />
</head>
<body>
<div id="header_wrap" class="outer">
......@@ -51,7 +51,7 @@
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="index.html">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
<section id="main_content" class="inner">
......@@ -80,7 +80,7 @@
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
>index</a></li>
<li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="index.html">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
</div>
......
......@@ -7,7 +7,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Quickstart (to get a demo up and running) &mdash; Converse.js 0.7.3 documentation</title>
<title>Quickstart (to get a demo up and running) &mdash; Converse.js 0.7.4 documentation</title>
<link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
......@@ -15,7 +15,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7.3',
VERSION: '0.7.4',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
......@@ -24,7 +24,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Converse.js 0.7.3 documentation" href="#" />
<link rel="top" title="Converse.js 0.7.4 documentation" href="#" />
</head>
<body>
<div id="header_wrap" class="outer">
......@@ -49,7 +49,7 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="#">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="#">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
<section id="main_content" class="inner">
......@@ -1045,7 +1045,7 @@ The query string will be included in the request with <tt class="docutils litera
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="#">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="#">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
</div>
......
# Sphinx inventory version 2
# Project: Converse.js
# Version: 0.7.3
# Version: 0.7.4
# The remainder of this file is compressed using zlib.
xm
{"];
......
......@@ -7,7 +7,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; Converse.js 0.7.3 documentation</title>
<title>Search &mdash; Converse.js 0.7.4 documentation</title>
<link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
......@@ -15,7 +15,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7.3',
VERSION: '0.7.4',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
......@@ -25,7 +25,7 @@
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="Converse.js 0.7.3 documentation" href="index.html" />
<link rel="top" title="Converse.js 0.7.4 documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
......@@ -55,7 +55,7 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="index.html">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
<section id="main_content" class="inner">
......@@ -100,7 +100,7 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li>
<li><a href="index.html">Converse.js 0.7.4 documentation</a> &raquo;</li>
</ul>
</div>
</div>
......
This diff is collapsed.
......@@ -48,9 +48,9 @@ copyright = u'2013, JC Brand'
# built documents.
#
# The short X.Y version.
version = '0.7.3'
version = '0.7.4'
# The full version, including alpha/beta/rc tags.
release = '0.7.3'
release = '0.7.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
......@@ -4,7 +4,7 @@
<meta charset='utf-8' />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="description" content="Converse.js: Open Source Browser-Based Instant Messaging" />
<meta name="description" content="Converse.js: A chat client for your website" />
<link rel="stylesheet" type="text/css" media="screen" href="stylesheets/stylesheet.css">
<link rel="stylesheet" type="text/css" media="screen" href="converse.css">
<script data-main="main" src="components/requirejs/require.js"></script>
......
{
"name": "converse.js",
"version": "0.7.3",
"version": "0.7.4",
"description": "Browser based XMPP instant messaging client",
"main": "main.js",
"directories": {
......
......@@ -465,42 +465,99 @@
var view = this.chatboxviews.get(contact_jid);
var message = 'This message is sent from this chatbox';
spyOn(view, 'sendMessage').andCallThrough();
view.$el.find('.chat-textarea').text(message);
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 2);
expect(converse.emit.callCount).toEqual(3);
expect(converse.emit.mostRecentCall.args, ['onMessageSend', message]);
var txt = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content').text();
expect(txt).toEqual(message);
expect(view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content').text()).toEqual(message);
}.bind(converse));
}, converse));
it("are sanitized to prevent Javascript injection attacks", $.proxy(function () {
it("is sanitized to prevent Javascript injection attacks", $.proxy(function () {
var contact_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
utils.openChatBoxFor(contact_jid);
var view = this.chatboxviews.get(contact_jid);
var message = 'This message contains <b>markup</b>';
var message = '<p>This message contains <em>some</em> <b>markup</b></p>';
spyOn(view, 'sendMessage').andCallThrough();
view.$el.find('.chat-textarea').text(message);
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
var txt = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content').text();
expect(txt).toEqual(message);
var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
}, converse));
it("can contain hyperlinks, which will be clickable", $.proxy(function () {
var contact_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
utils.openChatBoxFor(contact_jid);
var view = this.chatboxviews.get(contact_jid);
var message = 'This message contains a hyperlink: www.opkode.com';
spyOn(view, 'sendMessage').andCallThrough();
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('This message contains a hyperlink: <a target="_blank" href="http://www.opkode.com">www.opkode.com</a>');
}, converse));
it("will have properly escaped URLs", $.proxy(function () {
var contact_jid = mock.cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
utils.openChatBoxFor(contact_jid);
var view = this.chatboxviews.get(contact_jid);
spyOn(view, 'sendMessage').andCallThrough();
var message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
message = "https://en.wikipedia.org/wiki/Ender's_Game";
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender\'s_Game</a>');
message = "https://en.wikipedia.org/wiki/Ender%27s_Game";
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content');
expect(msg.text()).toEqual(message);
expect(msg.html()).toEqual('<a target="_blank" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender%27s_Game</a>');
}, converse));
}, converse));
}, converse));
describe("Special Messages", $.proxy(function () {
beforeEach(function () {
utils.closeAllChatBoxes();
utils.removeControlBox();
converse.roster.localStorage._clear();
utils.initConverse();
utils.createCurrentContacts();
utils.openControlBox();
utils.openContactsPanel();
});
it("'/clear' can be used to clear messages in a conversation", $.proxy(function () {
spyOn(converse, 'emit');
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
utils.openChatBoxFor(contact_jid);
var view = this.chatboxviews.get(contact_jid);
var message = 'This message is another sent from this chatbox';
// Lets make sure there is at least one message already
// (e.g for when this test is run on its own).
view.$el.find('.chat-textarea').val(message).text(message);
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
utils.sendMessage(view, message);
expect(view.model.messages.length > 0).toBeTruthy();
expect(view.model.messages.localStorage.records.length > 0).toBeTruthy();
expect(converse.emit).toHaveBeenCalledWith('onMessageSend', message);
......@@ -508,8 +565,7 @@
message = '/clear';
var old_length = view.model.messages.length;
spyOn(view, 'sendMessage').andCallThrough();
view.$el.find('.chat-textarea').val(message).text(message);
view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
utils.sendMessage(view, message);
expect(view.sendMessage).toHaveBeenCalled();
expect(view.model.messages.length, 0); // The messages must be removed from the modal
expect(view.model.messages.localStorage.records.length, 0); // And also from localStorage
......
......@@ -33,8 +33,8 @@
"bigint": "src/bigint",
"crypto.core": "components/otr/vendor/cryptojs/core",
"crypto.enc-base64": "components/otr/vendor/cryptojs/enc-base64",
"crypto.md5": "components/crypto-js/src/md5",
"crypto.evpkdf": "components/crypto-js/src/evpkdf",
"crypto.md5": "components/crypto-js-evanvosberg/src/md5",
"crypto.evpkdf": "components/crypto-js-evanvosberg/src/evpkdf",
"crypto.cipher-core": "components/otr/vendor/cryptojs/cipher-core",
"crypto.aes": "components/otr/vendor/cryptojs/aes",
"crypto.sha1": "components/otr/vendor/cryptojs/sha1",
......
......@@ -3,7 +3,7 @@
<html>
<head>
<title>Converse.js Tests</title>
<meta name="description" content="Converse.js: Open Source Browser-Based Instant Messaging" />
<meta name="description" content="Converse.js: A chat client for your website" />
<link rel="shortcut icon" type="image/png" href="components/jasmine/images/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="components/jasmine/src/html/jasmine.css">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheets/stylesheet.css">
......
......@@ -110,5 +110,10 @@
}
return this;
};
utils.sendMessage = function (chatboxview, message) {
chatboxview.$el.find('.chat-textarea').val(message);
chatboxview.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
};
return utils;
}));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment