From 037af6890fe6fdb84a08d3c86083e847c90ec0ad Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Tue, 22 Oct 2013 08:17:26 -0400 Subject: [PATCH] Fix vulnerability in handling _session argument of utils/save-prefs (#1489382) --- program/js/app.js | 305 +------------------------------------------------- 1 files changed, 7 insertions(+), 298 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 44962f1..77ec9d9 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -252,14 +252,12 @@ } else if (this.env.action == 'compose') { this.env.address_group_stack = []; - this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', - 'toggle-editor', 'list-adresses', 'pushgroup', 'search', 'reset-search', 'extwin', - 'insert-response', 'save-response']; + this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'pushgroup', 'search', 'reset-search', 'extwin']; if (this.env.drafts_mailbox) this.env.compose_commands.push('savedraft') - this.enable_command(this.env.compose_commands, 'identities', 'responses', true); + this.enable_command(this.env.compose_commands, 'identities', true); // add more commands (not enabled) $.merge(this.env.compose_commands, ['add-recipient', 'firstpage', 'previouspage', 'nextpage', 'lastpage']); @@ -268,23 +266,6 @@ this.env.spellcheck.spelling_state_observer = function(s) { ref.spellcheck_state(); }; this.env.compose_commands.push('spellcheck') this.enable_command('spellcheck', true); - } - - // init canned response functions - if (this.gui_objects.responseslist) { - $('a.insertresponse', this.gui_objects.responseslist) - .attr('unselectable', 'on') - .mousedown(function(e){ return rcube_event.cancel(e); }) - .mouseup(function(e){ - ref.command('insert-response', $(this).attr('rel')); - $(document.body).trigger('mouseup'); // hides the menu - return rcube_event.cancel(e); - }); - - // avoid textarea loosing focus when hitting the save-response button/link - for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) { - $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); }) - } } document.onmouseup = function(e){ return p.doc_mouse_up(e); }; @@ -393,7 +374,7 @@ break; case 'settings': - this.enable_command('preferences', 'identities', 'responses', 'save', 'folders', true); + this.enable_command('preferences', 'identities', 'save', 'folders', true); if (this.env.action == 'identities') { this.enable_command('add', this.env.identities_level < 2); @@ -414,9 +395,6 @@ parent.rcmail.enable_command('purge', this.env.messagecount); $("input[type='text']").first().select(); } - else if (this.env.action == 'responses') { - this.enable_command('add', true); - } if (this.gui_objects.identitieslist) { this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false}); @@ -433,22 +411,8 @@ this.sections_list.init(); this.sections_list.focus(); } - else if (this.gui_objects.subscriptionlist) { + else if (this.gui_objects.subscriptionlist) this.init_subscription_list(); - } - else if (this.gui_objects.responseslist) { - this.responses_list = new rcube_list_widget(this.gui_objects.responseslist, {multiselect:false, draggable:false, keyboard:false}); - this.responses_list.addEventListener('select', function(list){ - var win, id = list.get_single_selection(); - p.enable_command('delete', !!id && $.inArray(id, p.env.readonly_responses) < 0); - if (id && (win = p.get_frame_window(p.env.contentframe))) { - p.set_busy(true); - p.location_href({ _action:'edit-response', _key:id, _framed:1 }, win); - } - }); - this.responses_list.init(); - this.responses_list.focus(); - } break; @@ -735,13 +699,6 @@ case 'add': if (this.task == 'addressbook') this.load_contact(0, 'add'); - else if (this.task == 'settings' && this.env.action == 'responses') { - var frame; - if ((frame = this.get_frame_window(this.env.contentframe))) { - this.set_busy(true); - this.location_href({ _action:'add-response', _framed:1 }, frame); - } - } else if (this.task == 'settings') { this.identity_list.clear_selection(); this.load_identity(0, 'add-identity'); @@ -805,10 +762,7 @@ // addressbook task else if (this.task == 'addressbook') this.delete_contacts(); - // settings: canned response - else if (this.task == 'settings' && this.env.action == 'responses') - this.delete_response(); - // settings: user identities + // user settings task else if (this.task == 'settings') this.delete_identity(); break; @@ -1180,7 +1134,6 @@ // user settings commands case 'preferences': case 'identities': - case 'responses': case 'folders': this.goto_url('settings/' + command); break; @@ -3279,154 +3232,6 @@ return true; }; - this.insert_response = function(key) - { - var insert = this.env.textresponses[key] ? this.env.textresponses[key].text : null; - if (!insert) - return false; - - // insert into tinyMCE editor - if ($("input[name='_is_html']").val() == '1') { - var editor = tinyMCE.get(this.env.composebody); - editor.getWin().focus(); // correct focus in IE & Chrome - editor.selection.setContent(insert, { format:'text' }); - } - // replace selection in compose textarea - else { - var textarea = rcube_find_object(this.env.composebody), - selection = $(textarea).is(':focus') ? this.get_input_selection(textarea) : { start:0, end:0 }, - inp_value = textarea.value; - pre = inp_value.substring(0, selection.start), - end = inp_value.substring(selection.end, inp_value.length); - - // insert response text - textarea.value = pre + insert + end; - - // set caret after inserted text - this.set_caret_pos(textarea, selection.start + insert.length); - textarea.focus(); - } - }; - - /** - * Open the dialog to save a new canned response - */ - this.save_response = function() - { - var sigstart, text = '', strip = false; - - // get selected text from tinyMCE editor - if ($("input[name='_is_html']").val() == '1') { - var editor = tinyMCE.get(this.env.composebody); - editor.getWin().focus(); // correct focus in IE & Chrome - text = editor.selection.getContent({ format:'text' }); - - if (!text) { - text = editor.getContent({ format:'text' }); - strip = true; - } - } - // get selected text from compose textarea - else { - var textarea = rcube_find_object(this.env.composebody), sigstart; - if (textarea && $(textarea).is(':focus')) { - text = this.get_input_selection(textarea).text; - } - - if (!text && textarea) { - text = textarea.value; - strip = true; - } - } - - // strip off signature - if (strip) { - sigstart = text.indexOf('-- \n'); - if (sigstart > 0) { - text = text.substring(0, sigstart); - } - } - - // show dialog to enter a name and to modify the text to be saved - var buttons = {}, - html = '<form class="propform">' + - '<div class="prop block"><label>' + this.get_label('responsename') + '</label>' + - '<input type="text" name="name" id="ffresponsename" size="40" /></div>' + - '<div class="prop block"><label>' + this.get_label('responsetext') + '</label>' + - '<textarea name="text" id="ffresponsetext" cols="40" rows="8"></textarea></div>' + - '</form>'; - - buttons[this.gettext('save')] = function(e) { - var name = $('#ffresponsename').val(), - text = $('#ffresponsetext').val(); - - if (!text) { - $('#ffresponsetext').select(); - return false; - } - if (!name) - name = text.substring(0,40); - - var lock = ref.display_message(ref.get_label('savingresponse'), 'loading'); - ref.http_post('settings/responses', { _insert:1, _name:name, _text:text }, lock); - $(this).dialog('close'); - }; - - buttons[this.gettext('cancel')] = function() { - $(this).dialog('close'); - }; - - this.show_popup_dialog(html, this.gettext('savenewresponse'), buttons); - - $('#ffresponsetext').val(text); - $('#ffresponsename').select(); - }; - - this.add_response_item = function(response) - { - var key = response.key; - this.env.textresponses[key] = response; - - // append to responses list - if (this.gui_objects.responseslist) { - var li = $('<li>').appendTo(this.gui_objects.responseslist); - $('<a>').addClass('insertresponse active') - .attr('href', '#') - .attr('rel', key) - .html(this.quote_html(response.name)) - .appendTo(li) - .mousedown(function(e){ - return rcube_event.cancel(e); - }) - .mouseup(function(e){ - ref.command('insert-response', key); - $(document.body).trigger('mouseup'); // hides the menu - return rcube_event.cancel(e); - }); - } - }; - - this.edit_responses = function() - { - // TODO: implement inline editing of responses - }; - - this.delete_response = function(key) - { - if (!key && this.responses_list) { - var selection = this.responses_list.get_selection(); - key = selection[0]; - } - - // submit delete request - if (key && confirm(this.get_label('deleteresponseconfirm'))) { - this.http_post('settings/delete-response', { _key: key }, false); - return true; - } - - return false; - }; - this.stop_spellchecking = function() { var ed; @@ -5327,42 +5132,6 @@ } }; - this.update_response_row = function(response, oldkey) - { - var row, col, list = this.responses_list; - - if (list && oldkey && list.rows[oldkey] && (row = list.rows[oldkey].obj)) { - $(row.cells[0]).html(response.name); - // update references because the key likely changed - row.id = 'rcmrow'+response.key; - list.init_row(row); - list.select(response.key); - delete list.rows[oldkey]; - } - else if (list) { - row = $('<tr>').attr('id', 'rcmrow'+response.key).get(0); - col = $('<td>').addClass('name').html(response.name).appendTo(row); - list.insert_row(row); - list.select(response.key); - } - }; - - this.remove_response = function(key) - { - var frame; - - if (this.env.textresponses) { - delete this.env.textresponses[key]; - } - - if (this.responses_list) { - this.responses_list.remove_row(key); - if (this.env.contentframe && (frame = this.get_frame_window(this.env.contentframe))) { - frame.location.href = this.env.blankpage; - } - } - }; - /*********************************************************/ /********* folder manager methods *********/ @@ -6041,7 +5810,7 @@ }; // open a jquery UI dialog with the given content - this.show_popup_dialog = function(html, title, buttons) + this.show_popup_dialog = function(html, title) { // forward call to parent window if (this.is_framed()) { @@ -6053,7 +5822,6 @@ .html(html) .dialog({ title: title, - buttons: buttons, modal: true, resizable: true, width: 580, @@ -6063,7 +5831,7 @@ // 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+75 + (buttons ? 50 : 0)), width: Math.min(w-20, width+50) }) + 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 (!?) }; @@ -6904,14 +6672,6 @@ /********* helper methods *********/ /********************************************************/ - /** - * Quote html entities - */ - this.quote_html = function(str) - { - return String(str).replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); - }; - // get window.opener.rcmail if available this.opener = function() { @@ -6974,57 +6734,6 @@ range.moveStart('character', pos); range.select(); } - }; - - // get selected text from an input field - // http://stackoverflow.com/questions/7186586/how-to-get-the-selected-text-in-textarea-using-jquery-in-internet-explorer-7 - this.get_input_selection = function(obj) - { - var start = 0, end = 0, - normalizedValue, range, - textInputRange, len, endRange; - - if (typeof obj.selectionStart == "number" && typeof obj.selectionEnd == "number") { - normalizedValue = obj.value; - start = obj.selectionStart; - end = obj.selectionEnd; - } - else { - range = document.selection.createRange(); - - if (range && range.parentElement() == obj) { - len = obj.value.length; - normalizedValue = obj.value; //.replace(/\r\n/g, "\n"); - - // create a working TextRange that lives only in the input - textInputRange = obj.createTextRange(); - textInputRange.moveToBookmark(range.getBookmark()); - - // Check if the start and end of the selection are at the very end - // of the input, since moveStart/moveEnd doesn't return what we want - // in those cases - endRange = obj.createTextRange(); - endRange.collapse(false); - - if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { - start = end = len; - } - else { - start = -textInputRange.moveStart("character", -len); - start += normalizedValue.slice(0, start).split("\n").length - 1; - - if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { - end = len; - } - else { - end = -textInputRange.moveEnd("character", -len); - end += normalizedValue.slice(0, end).split("\n").length - 1; - } - } - } - } - - return { start:start, end:end, text:normalizedValue.substr(start, end-start) }; }; // disable/enable all fields of a form -- Gitblit v1.9.1