MARKMIN - Sanitizing

36 views
Skip to first unread message

Paul Ellis

unread,
Apr 25, 2019, 7:19:44 AM4/25/19
to web2py-users
I am using an editable span with some js to submit the input via ajax to the server. The span is only editable by admins.

To give them some formatting options they can use MARKMIN in the span.

The problem is it only seems to be one directional.
How can I take the processed HTML and turn it back into MARKMIN in order to allow editing?

or at least sanitize it that I can be sure no malicious code has been submitted so I can save the MARKMIN in the db.

 js that sends the span contents.
$("document").ready(function() {

   
// set the event listeners on the edit button
    $
("button[name='buttonedit']").click(function() {
       
var panel = $(this)[0].previousSibling
        panel
.innerText = panel.getAttribute("data-raw")
        panel
.setAttribute("contenteditable", "true")
       
// console.log(panel)
        $
(this).hide()
        $
(this)[0].nextSibling.setAttribute("style", "display:true")
   
})
    $
("button[name='buttonsave']").click(function() {
        $
(this).disabled = true
       
var xhttp = new XMLHttpRequest();
        xhttp
.open('POST', '/assist/update_info_panel', true);
        xhttp
.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       
var panel = $(this)[0].previousElementSibling.previousElementSibling
       
var body = {
           
'pid': panel.id,
           
'body': panel.innerText,
       
};
       
// console.log(body);
        xhttp
.onreadystatechange = function() {
           
// debug code
           
// if (this.readyState == 4) {
           
//     console.log(this);
           
// };
           
if (this.readyState == 4 && this.status == 200) {
               
var rObj = JSON.parse(this.responseText);
                $
("span#"+rObj.pid).replaceWith(rObj.body)
                $
("span#"+rObj.pid)
                   
.next().attr("style", "display:true")
                   
.next().attr("style", "display:None")
                $
("span#"+rObj.pid).find("a").attr("target", "_blank")

           
}
       
};
        xhttp
.send(JSON.stringify(body));
   
})
})

the controller function that receives the markmin (via json) and returns the HTML.

In order to allow editing the raw markmin is stored in a data attribute. I feel this is very unsafe which is why I am asking for help.
def update_info_panel():
   
if auth.has_membership('assistant_admin', cached=True):
        raw_json
= None
       
for key in request.vars.keys():
           
if len(key) > 10:
                raw_json
= key
        inData
= Storage(json.loads(raw_json))
        pid
= inData.pid[5:]
        record
= db.product[pid]
        assist_info
= inData.body
       
if record:
            record
.update_record(assist_info=assist_info)
        body
= {
           
'pid': inData.pid,
           
'body': SPAN(MARKMIN(assist_info),
                    _id
=inData.pid,
                    _name
='info_panel',
                    _contenteditable
='false',
                    data
= {'raw': assist_info}
                   
).__str__()
           
}
       
return json.dumps(body)
   
else:
       
pass

The section of the view which holds the span and edit buttons.
        <div id='info_box' class='well'>
            {{try:}}
                {{for item in extra_info:}}
                    {{=DIV(
                        SPAN(MARKMIN(item['info']),
                            _id= 'info_{0}'.format(item['pid']),
                            _name= 'info_panel',
                            _contenteditable= 'false',
                            _style="display:block",
                            data= {
                                'raw':item['info'] if auth.has_membership('assistant_admin') else '',
                                },
                            ),
                        BUTTON(SPAN(_class="glyphicon glyphicon-pencil"),
                            _class='btn btn-sm btn-default', _name='buttonedit')\
                                if auth.has_membership('assistant_admin') else '',
                        BUTTON(SPAN(_class='glyphicon glyphicon-floppy-disk'),
                            _class="btn btn-sm btn-primary", _name="buttonsave",
                            _style="display:none")\
                                if auth.has_membership('assistant_admin') else '',
                        _id= 'box_{0}'.format(item['id']),
                        _style='display:none',
                        )}}
                    {{pass}}
            {{except Exception as e:}}
                {{print e}}
                {{pass}}
       
</div>

The function looks and works great. Apart from the Italic formatting cutting the JSON string short, resulting in invalid JSON and me being very uneasy about saving raw user input into the db and then letting it back out again.

As a side question. Is there different way to add the JSON string to the ajax request in js so that it is accessible from somwhere other than as a key in request.vars?




villas

unread,
Apr 29, 2019, 1:06:50 PM4/29/19
to web2py-users
Hi Paul

If you are worried about saving dodgy text in the DB,  you could sanitize it first using XML()

e.g.

XML('<script>dodgy();</script>**Hello**',sanitize=True).xml()

&lt;script&gt;&lt;/script&gt;**Hello**

Paul Ellis

unread,
Apr 29, 2019, 2:30:29 PM4/29/19
to web2py-users
Hey Villas,

thanks. I actually thought that the XML sanitization would break the MARKMIN conversion.... but it doesn't.

I probably should have tested that first.

Regards

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/pjrche-oZl0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages