How to add a field to POST values in CKeditor upload

I use django and ckeditor to provide wysiwyg taste to TextEdits. I would like to use CKEditor file upload function (in filebrowser / image dialog), but the POST made by CKEditor to upload the image just contains the file data.

This is a problem for CSRF checking. I couldn't find in CKEditor documentation and source a place to change the POST data for file upload, to add django's csrf_token in POST data.

As a workaround, I can change the filebrowserUploadUrl parameters to include csrf data in upload URL, use the @csrf_exempt for the upload view, and check request.GET parameters to check csrf. But is this solution safe ?

Anyway, if somebody knows how to include csrf token directly within CKEditor file upload POST data, i'm strongly interested...

Answers:

Answer

You can register for the dialogDefinition event, and completely rewrite the upload tab, thus:

CKEDITOR.on('dialogDefinition', function (ev) {
  var dialogName = ev.data.name;
  var dialogDefinition = ev.data.definition;
  if (dialogName == 'image') {
    dialogDefinition.removeContents('Upload');
    dialogDefinition.addContents({
      title: "Upload",
      id: "upload",
      label: "Upload",
      elements: [{
        type: "html",
        html: '<form><input id="imageupload" type="file" name="files[]" />{%csrf_token%}</form>'
      }]
    });
   }
});

This is an untested simplification of my real-world version, but hopefully it shows the idea.

This does not set the URL field in the image dialog, so clicking OK on the dialog will give you an error message. You will need to set that on a successful upload, thus:

CKEDITOR.dialog.getCurrent().getContentElement('info', 'txtUrl').setValue(theURL);
Answer

The extra data sent to the server is passed by get request. I was trying to add extra data and finally achieve this adding to a url parameters of the form that is used to send data

CKEDITOR.on('dialogDefinition', function(ev)
   {
     var dialogName = ev.data.name;
     var dialogDefinition = ev.data.definition;
     if (dialogName == 'image')
     {
           dialogDefinition.contents[2].elements[0].action += '&pin=123456';
            /* 2 is the upload tab it have two elements 0=apparently is the
            and 1: is the button to perform the upload, in 0 have the action property with the parameters of the get request simply adding the new data               
              */ 

     }
   });
Answer

It seems that there is no way to add data to ckeditor upload data without editing ckeditor source code. The source code to be modified is plugins/dialogui/plugin.js, around lines 1440 in ckeditor 3.6.2, where ckeditor creates the form used by the upload iframe.

// ADDED TO CKEDITOR CODE %<
var csrfitems = document.getElementsByName("csrfmiddlewaretoken")
var csrftoken = ""
if(csrfitems.length > 0)
    csrftoken = csrfitems[0].value
// >% END OF ADDED CODE
if ( elementDefinition.size )
    size = elementDefinition.size - ( CKEDITOR.env.ie  ? 7 : 0 );   // "Browse" button is bigger in IE.
frameDocument.$.write( [ '<html dir="' + langDir + '" lang="' + langCode + '"><head><title></title></head><body style="margin: 0; overflow: hidden; background: transparent;">',
'<form enctype="multipart/form-data" method="POST" dir="' + langDir + '" lang="' + langCode + '" action="',
CKEDITOR.tools.htmlEncode( elementDefinition.action ),
'">',
// ADDED TO CKEDITOR CODE
    '<input type="hidden" name="csrfmiddlewaretoken" value="',csrftoken,'"/>',
    // >% END OF ADDED CODE
'<input type="file" name="',
CKEDITOR.tools.htmlEncode( elementDefinition.id || 'cke_upload' ),
'" size="',
CKEDITOR.tools.htmlEncode( size > 0 ? size : "" ),
'" />',
'</form>',

And now we can use safely upload in ckeditor with django

Answer

I experienced a similar problem when integrating image uploading through CKEditor for Elgg. The least intrusive solution I came up with was to bind to the onClick event for the submit button and modify the form directly from that:

CKEDITOR.on('dialogDefinition', function (ev) {
    var dialogName = ev.data.name;
    var dialogDefinition = ev.data.definition;

    if (dialogName === 'image') {
        var uploadTab = dialogDefinition.getContents('Upload');

        for (var i = 0; i < uploadTab.elements.length; i++) {
            var el = uploadTab.elements[i];

            if (el.type !== 'fileButton') {
                continue;
            }

            // add onClick for submit button to add inputs or rewrite the URL
            var onClick = el.onclick;

            el.onClick = function(evt) {
                var dialog = this.getDialog();
                var fb = dialog.getContentElement(this['for'][0], this['for'][1]);
                var action = fb.getAction();
                var editor = dialog.getParentEditor();
                editor._.filebrowserSe = this;

                // if using jQuery
                $(fb.getInputElement().getParent().$).append('<input type="hidden" name="foo" value="bar">');

                // modifying the URL
                fb.getInputElement().getParent().$.action = '/my/new/action?with&query&params=1';


                if (onClick && onClick.call(evt.sender, evt) === false) {
                        return false;
                }

                return true;
            };
        }
    }
});
Answer

The question is too old but...

Version 4.5 you can add hook into any request

editor.on( 'fileUploadRequest', function( evt ) {
    var xhr = evt.data.fileLoader.xhr;

    xhr.setRequestHeader( 'Cache-Control', 'no-cache' );
    xhr.setRequestHeader( 'csrf header ', 'HEADER' );
    xhr.withCredentials = true;
} );
Answer

Providing you are sending a CSFR token in the URL across HTTPS it should be ok to do that (from a security pint of view) and also a lot easier to deal with.

That assumes django can read that variable or you are able to easily mod django. These answers trying to alter CKeditor seem a bit too much work imo.

As long as your CSFR_token is being sent by the users browser in a secure way to the server it doesn't matter if it is via POST or GET. The security concern at play is a man in the middle attack, i.e you don't want a users CSFR_token being broadcast in plain text.

Strictly speaking this kind of data should be sent as POST according to the HTTP spec but this seems like a situation where 'misusing' the GET protocol might be acceptable as you don't have control of the CKEditor code in a particularly elegant way.

Also you could get caught out if CKEditor changes things in an upgrade, passing the token via the URL will always work.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.