From 752eedd9647468aa40028f5e73b80adb88957b34 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Wed, 31 Oct 2012 04:37:04 -0400 Subject: [PATCH] Fix possible HTTP DoS on error in keep-alive requests (#1488782) --- program/js/app.js | 127 ++++++++++++++++++++++-------------------- 1 files changed, 66 insertions(+), 61 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 8d02f6f..17f423e 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -60,6 +60,8 @@ beforeSend: function(xmlhttp){ xmlhttp.setRequestHeader('X-Roundcube-Request', ref.env.request_token); } }); + $(window).bind('beforeunload', function() { rcmail.unload = true; }); + // set environment variable(s) this.set_env = function(p, value) { @@ -1457,29 +1459,21 @@ this.doc_mouse_up = function(e) { - var model, list, li, id; + var model, list, id; // ignore event if jquery UI dialog is open if ($(rcube_event.get_target(e)).closest('.ui-dialog, .ui-widget-overlay').length) return; - if (list = this.message_list) { - if (!rcube_mouse_is_over(e, list.list.parentNode)) - list.blur(); - else - list.focus(); + if (list = this.message_list) model = this.env.mailboxes; - } - else if (list = this.contact_list) { - if (!rcube_mouse_is_over(e, list.list.parentNode)) - list.blur(); - else - list.focus(); + else if (list = this.contact_list) model = this.env.contactfolders; - } - else if (this.ksearch_value) { + else if (this.ksearch_value) this.ksearch_blur(); - } + + if (list && !rcube_mouse_is_over(e, list.list.parentNode)) + list.blur(); // handle mouse release when dragging if (this.drag_active && model && this.env.last_folder_target) { @@ -1622,7 +1616,7 @@ for (i=0; i<cols.length; i++) if (cols[i].id && cols[i].id.match(/^rcm/)) { name = cols[i].id.replace(/^rcm/, ''); - this.env.coltypes.push(name == 'to' ? 'from' : name); + this.env.coltypes.push(name); } if ((found = $.inArray('flag', this.env.coltypes)) >= 0) @@ -1901,7 +1895,7 @@ // make sure new columns are added at the end of the list var i, idx, name, newcols = [], oldcols = this.env.coltypes; for (i=0; i<oldcols.length; i++) { - name = oldcols[i] == 'to' ? 'from' : oldcols[i]; + name = oldcols[i]; idx = $.inArray(name, cols); if (idx != -1) { newcols.push(name); @@ -2648,34 +2642,37 @@ // set a specific flag to one or more messages this.mark_message = function(flag, uid) { - var a_uids = [], r_uids = [], len, n, id, - selection = this.message_list ? this.message_list.get_selection() : []; + var a_uids = [], r_uids = [], len, n, id, selection, + list = this.message_list; if (uid) a_uids[0] = uid; else if (this.env.uid) a_uids[0] = this.env.uid; - else if (this.message_list) { + else if (list) { + selection = list.get_selection(); for (n=0, len=selection.length; n<len; n++) { a_uids.push(selection[n]); } } - if (!this.message_list) + if (!list) r_uids = a_uids; - else + else { + list.focus(); for (n=0, len=a_uids.length; n<len; n++) { id = a_uids[n]; - if ((flag=='read' && this.message_list.rows[id].unread) - || (flag=='unread' && !this.message_list.rows[id].unread) - || (flag=='delete' && !this.message_list.rows[id].deleted) - || (flag=='undelete' && this.message_list.rows[id].deleted) - || (flag=='flagged' && !this.message_list.rows[id].flagged) - || (flag=='unflagged' && this.message_list.rows[id].flagged)) + if ((flag=='read' && list.rows[id].unread) + || (flag=='unread' && !list.rows[id].unread) + || (flag=='delete' && !list.rows[id].deleted) + || (flag=='undelete' && list.rows[id].deleted) + || (flag=='flagged' && !list.rows[id].flagged) + || (flag=='unflagged' && list.rows[id].flagged)) { r_uids.push(id); } } + } // nothing to do if (!r_uids.length && !this.select_all_mode) @@ -3273,8 +3270,7 @@ input_message = $("[name='_message']"), message = input_message.val(), is_html = ($("input[name='_is_html']").val() == '1'), - sig = this.env.identity, - sig_separator = this.env.sig_above && (this.env.compose_mode == 'reply' || this.env.compose_mode == 'forward') ? '---' : '-- '; + sig = this.env.identity; // enable manual signature insert if (this.env.signatures && this.env.signatures[id]) { @@ -3287,12 +3283,8 @@ if (!is_html) { // remove the 'old' signature if (show_sig && sig && this.env.signatures && this.env.signatures[sig]) { - - sig = this.env.signatures[sig].is_html ? this.env.signatures[sig].plain_text : this.env.signatures[sig].text; + sig = this.env.signatures[sig].text; sig = sig.replace(/\r\n/g, '\n'); - - if (!sig.match(/^--[ -]\n/m)) - sig = sig_separator + '\n' + sig; p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig); if (p >= 0) @@ -3300,11 +3292,8 @@ } // add the new signature string if (show_sig && this.env.signatures && this.env.signatures[id]) { - sig = this.env.signatures[id]['is_html'] ? this.env.signatures[id]['plain_text'] : this.env.signatures[id]['text']; + sig = this.env.signatures[id].text; sig = sig.replace(/\r\n/g, '\n'); - - if (!sig.match(/^--[ -]\n/m)) - sig = sig_separator + '\n' + sig; if (this.env.sig_above) { if (p >= 0) { // in place of removed signature @@ -3369,21 +3358,8 @@ } } - if (this.env.signatures[id]) { - if (this.env.signatures[id].is_html) { - sig = this.env.signatures[id].text; - if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/m)) - sig = sig_separator + '<br />' + sig; - } - else { - sig = this.env.signatures[id].text; - if (!sig.match(/^--[ -]\r?\n/m)) - sig = sig_separator + '\n' + sig; - sig = '<pre>' + sig + '</pre>'; - } - - sigElem.innerHTML = sig; - } + if (this.env.signatures[id]) + sigElem.innerHTML = this.env.signatures[id].html; } this.env.identity = id; @@ -3998,8 +3974,7 @@ // if a group is currently selected, and there is at least one contact selected // thend we can enable the group-remove-selected command - this.enable_command('group-remove-selected', typeof this.env.group != 'undefined' && list.selection.length > 0); - + this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0); this.enable_command('compose', this.env.group || list.selection.length > 0); this.enable_command('edit', id && writable); this.enable_command('delete', list.selection.length && writable); @@ -5598,6 +5573,32 @@ this.messages = {}; }; + // open a jquery UI dialog with the given content + this.show_popup_dialog = function(html, title) + { + // forward call to parent window + if (this.is_framed()) { + parent.rcmail.show_popup_dialog(html, title); + return; + } + + var popup = $('<div class="popup">') + .html(html) + .dialog({ + title: title, + modal: true, + resizable: true, + width: 580, + close: function(event, ui) { $(this).remove() } + }); + + // resize and center popup + var win = $(window), w = win.width(), h = win.height(), + width = popup.width(), height = popup.height(); + popup.dialog('option', { height: Math.min(h-40, height+50), width: Math.min(w-20, width+50) }) + .dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?) + }; + // mark a mailbox as selected and set environment variable this.select_folder = function(name, prefix, encode) { @@ -5644,7 +5645,7 @@ // for reordering column array (Konqueror workaround) // and for setting some message list global variables - this.set_message_coltypes = function(coltypes, repl) + this.set_message_coltypes = function(coltypes, repl, smart_col) { var list = this.message_list, thead = list ? list.list.tHead : null, @@ -5672,7 +5673,7 @@ for (n=0, len=this.env.coltypes.length; n<len; n++) { col = this.env.coltypes[n]; - if ((cell = thead.rows[0].cells[n]) && (col=='from' || col=='to')) { + if ((cell = thead.rows[0].cells[n]) && (col == 'from' || col == 'to' || col == 'fromto')) { cell.id = 'rcm'+col; // if we have links for sorting, it's a bit more complicated... if (cell.firstChild && cell.firstChild.tagName.toLowerCase()=='a') { @@ -5680,7 +5681,7 @@ cell.onclick = function(){ return rcmail.command('sort', this.__col, this); }; cell.__col = col; } - cell.innerHTML = this.get_label(col); + cell.innerHTML = this.get_label(col == 'fromto' ? smart_col : col); } } } @@ -6129,6 +6130,10 @@ this.set_busy(false, null, lock); request.abort(); + // don't display error message on page unload (#1488547) + if (this.unload) + return; + if (request.status && errmsg) this.display_message(this.get_label('servererror') + ' (' + errmsg + ')', 'error'); else if (status == 'timeout') @@ -6138,9 +6143,9 @@ // re-send keep-alive requests after 30 seconds if (action == 'keep-alive') - setTimeout(function(){ ref.keep_alive(); }, 30000); + setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000); else if (action == 'check-recent') - setTimeout(function(){ ref.check_for_recent(false); }, 30000); + setTimeout(function(){ ref.check_for_recent(false); ref.start_keepalive(); }, 30000); }; // post the given form to a hidden iframe -- Gitblit v1.9.1