Example #1
0
    def test_markup_choice(self):
        """
        Check the distinction between Creole and Markdown pages
        """
        offering = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        memb = Member.objects.get(offering=offering, person__userid="ggbaker")

        p = Page(offering=offering, label="Test")
        p.save()
        v1 = PageVersion(page=p,
                         title="T1",
                         wikitext='A //test//.',
                         editor=memb,
                         comment="original page")
        v1.save()
        self.assertEqual(v1.html_contents(), '<p>A <em>test</em>.</p>')

        v2 = PageVersion(page=p,
                         title="T1",
                         wikitext='A *test*.',
                         editor=memb,
                         comment="original page")
        v2.set_markup('markdown')
        v2.save()
        self.assertEqual(v2.html_contents(), '<p>A <em>test</em>.</p>')
Example #2
0
    def test_html_safety(self):
        """
        Check that we're handling HTML in a safe way
        """
        html = markup_to_html('<p>Foo</em>', 'html')
        self.assertEqual(html, '<p>Foo</p>')

        html = markup_to_html('Foo<script>alert()</script>', 'html')
        self.assertEqual(html, 'Fooalert()')

        # some junky MSWord-like markup
        html = markup_to_html('Foo<p class="home"><Span style="font-size: 500%">bar</Span></P>', 'html', restricted=True)
        self.assertEqual(html, 'Foo<p>bar</p>')

        html = markup_to_html('A&nbsp;&nbsp;<p>&nbsp;</p><table cellpadding="10"><tr><td colspan=4>B</td></tr></table>',
                              'html', restricted=True)
        self.assertEqual(html, 'A&nbsp;&nbsp;<p>&nbsp;</p>B')


        # unsafe if we ask for it
        html = markup_to_html('Foo<script>alert()</script>', 'html', html_already_safe=True)
        self.assertEqual(html, 'Foo<script>alert()</script>')

        # PageVersions should be saved only with safe HTML
        offering = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        memb = Member.objects.get(offering=offering, person__userid="ggbaker")

        p = Page(offering=offering, label="Test")
        p.save()
        v1 = PageVersion(page=p, title="T1", wikitext='<em>Some</em> <script>HTML</script>', editor=memb)
        v1.set_markup('html')
        v1.save()

        self.assertEqual(v1.wikitext, '<em>Some</em> HTML')
Example #3
0
    def save(self, editor, *args, **kwargs):
        # create the PageVersion object: distribute the self.cleaned_data values appropriately
        wikitext = self.cleaned_data['markup_content']
        comment = self.cleaned_data['comment']
        title = self.cleaned_data['title']
        pv = PageVersion(title=title, wikitext=wikitext, comment=comment, editor=editor)
        pv.set_markup(self.cleaned_data['_markup'])
        pv.set_math(self.cleaned_data['_math'])

        self.instance.offering = self.offering
        pg = super(EditPageForm, self).save(*args, **kwargs)
        pv.page=self.instance
        pv.save()
        return pg
Example #4
0
    def test_markup_choice(self):
        """
        Check the distinction between Creole and Markdown pages
        """
        offering = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        memb = Member.objects.get(offering=offering, person__userid="ggbaker")

        p = Page(offering=offering, label="Test")
        p.save()
        v1 = PageVersion(page=p, title="T1", wikitext='A //test//.', editor=memb, comment="original page")
        v1.save()
        self.assertEqual(v1.html_contents(), '<p>A <em>test</em>.</p>')

        v2 = PageVersion(page=p, title="T1", wikitext='A *test*.', editor=memb, comment="original page")
        v2.set_markup('markdown')
        v2.save()
        self.assertEqual(v2.html_contents(), '<p>A <em>test</em>.</p>')
Example #5
0
    def test_html_safety(self):
        """
        Check that we're handling HTML in a safe way
        """
        html = markup_to_html('<p>Foo</em>', 'html')
        self.assertEqual(html, '<p>Foo</p>')

        html = markup_to_html('Foo<script>alert()</script>', 'html')
        self.assertEqual(html, 'Fooalert()')

        # some junky MSWord-like markup
        html = markup_to_html(
            'Foo<p class="home"><Span style="font-size: 500%">bar</Span></P>',
            'html',
            restricted=True)
        self.assertEqual(html, 'Foo<p>bar</p>')

        html = markup_to_html(
            'A&nbsp;&nbsp;<p>&nbsp;</p><table cellpadding="10"><tr><td colspan=4>B</td></tr></table>',
            'html',
            restricted=True)
        self.assertEqual(html, 'A&nbsp;&nbsp;<p>&nbsp;</p>B')

        # unsafe if we ask for it
        html = markup_to_html('Foo<script>alert()</script>',
                              'html',
                              html_already_safe=True)
        self.assertEqual(html, 'Foo<script>alert()</script>')

        # PageVersions should be saved only with safe HTML
        offering = CourseOffering.objects.get(slug=TEST_COURSE_SLUG)
        memb = Member.objects.get(offering=offering, person__userid="ggbaker")

        p = Page(offering=offering, label="Test")
        p.save()
        v1 = PageVersion(page=p,
                         title="T1",
                         wikitext='<em>Some</em> <script>HTML</script>',
                         editor=memb)
        v1.set_markup('html')
        v1.save()

        self.assertEqual(v1.wikitext, '<em>Some</em> HTML')
Example #6
0
def _pages_from_json(request, offering, data):
    with django.db.transaction.atomic():
        try:
            data = data.decode('utf-8-sig')
        except UnicodeDecodeError:
            raise ValidationError("Bad UTF-8 data in file.")

        try:
            data = json.loads(data)
        except ValueError as e:
            raise ValidationError('JSON decoding error.  Exception was: "' +
                                  str(e) + '"')

        if not isinstance(data, dict):
            raise ValidationError(
                'Outer JSON data structure must be an object.')
        if 'userid' not in data or 'token' not in data:
            raise ValidationError(
                'Outer JSON data object must contain keys "userid" and "token".'
            )
        if 'pages' not in data:
            raise ValidationError(
                'Outer JSON data object must contain keys "pages".')
        if not isinstance(data['pages'], list):
            raise ValidationError('Value for "pages" must be a list.')

        try:
            user = Person.objects.get(userid=data['userid'])
            member = Member.objects.exclude(role='DROP').get(person=user,
                                                             offering=offering)
        except (Person.DoesNotExist, Member.DoesNotExist):
            raise ValidationError('Person with that userid does not exist.')

        if 'pages-token' not in user.config or user.config[
                'pages-token'] != data['token']:
            e = ValidationError('Could not validate authentication token.')
            e.status = 403
            raise e

        # if we get this far, the user is authenticated and we can start processing the pages...

        for i, pdata in enumerate(data['pages']):
            if not isinstance(pdata, dict):
                raise ValidationError(
                    'Page #%i entry structure must be an object.' % (i))
            if 'label' not in pdata:
                raise ValidationError(
                    'Page #%i entry does not have a "label".' % (i))

            # handle changes to the Page object
            pages = Page.objects.filter(offering=offering,
                                        label=pdata['label'])
            if pages:
                page = pages[0]
                old_ver = page.current_version()
            else:
                page = Page(offering=offering, label=pdata['label'])
                old_ver = None

            # check write permissions

            # mock the request object enough to satisfy _check_allowed()
            class FakeRequest(object):
                is_authenticated = True

            fake_request = FakeRequest()
            fake_request.user = FakeRequest()
            fake_request.user.username = user.userid

            if old_ver:
                m = _check_allowed(fake_request, offering, page.can_write,
                                   page.editdate())
            else:
                m = _check_allowed(fake_request, offering,
                                   offering.page_creators())
            if not m:
                raise ValidationError('You can\'t edit page #%i.' % (i))

            # handle Page attributes
            if 'can_read' in pdata:
                if type(pdata['can_read']
                        ) != str or pdata['can_read'] not in ACL_DESC:
                    raise ValidationError(
                        'Page #%i "can_read" value must be one of %s.' %
                        (i, ','.join(list(ACL_DESC.keys()))))

                page.can_read = pdata['can_read']

            if 'can_write' in pdata:
                if type(pdata['can_write']
                        ) != str or pdata['can_write'] not in WRITE_ACL_DESC:
                    raise ValidationError(
                        'Page #%i "can_write" value must be one of %s.' %
                        (i, ','.join(list(WRITE_ACL_DESC.keys()))))
                if m.role == 'STUD':
                    raise ValidationError(
                        'Page #%i: students can\'t change can_write value.' %
                        (i))
                page.can_write = pdata['can_write']

            if 'new_label' in pdata:
                if type(pdata['new_label']) != str:
                    raise ValidationError(
                        'Page #%i "new_label" value must be a string.' % (i))
                if m.role == 'STUD':
                    raise ValidationError(
                        'Page #%i: students can\'t change label value.' % (i))
                if Page.objects.filter(offering=offering,
                                       label=pdata['new_label']):
                    raise ValidationError(
                        'Page #%i: there is already a page with that "new_label".'
                        % (i))

                page.label = pdata['new_label']

            page.save()

            # handle PageVersion changes
            ver = PageVersion(page=page, editor=member)

            if 'title' in pdata:
                if type(pdata['title']) != str:
                    raise ValidationError(
                        'Page #%i "title" value must be a string.' % (i))

                ver.title = pdata['title']
            elif old_ver:
                ver.title = old_ver.title
            else:
                raise ValidationError('Page #%i has no "title" for new page.' %
                                      (i))

            if 'comment' in pdata:
                if type(pdata['comment']) != str:
                    raise ValidationError(
                        'Page #%i "comment" value must be a string.' % (i))

                ver.comment = pdata['comment']

            if 'use_math' in pdata:
                if type(pdata['use_math']) != bool:
                    raise ValidationError(
                        'Page #%i "comment" value must be a boolean.' % (i))

                ver.set_math(pdata['use_math'])

            if 'markup' in pdata:
                if isinstance(pdata['markup'], str):
                    raise ValidationError(
                        'Page #%i "markup" value must be a string.' % (i))

                ver.set_markup(pdata['markup'])

            if 'wikitext-base64' in pdata:
                if type(pdata['wikitext-base64']) != str:
                    raise ValidationError(
                        'Page #%i "wikitext-base64" value must be a string.' %
                        (i))
                try:
                    wikitext = base64.b64decode(
                        pdata['wikitext-base64']).decode('utf8')
                except TypeError:
                    raise ValidationError(
                        'Page #%i "wikitext-base64" contains bad base BASE64 data.'
                        % (i))

                ver.wikitext = wikitext
            elif 'wikitext' in pdata:
                if type(pdata['wikitext']) != str:
                    raise ValidationError(
                        'Page #%i "wikitext" value must be a string.' % (i))

                ver.wikitext = pdata['wikitext']
            elif old_ver:
                ver.wikitext = old_ver.wikitext
            else:
                raise ValidationError(
                    'Page #%i has no wikitext for new page.' % (i))

            ver.save()

        return user
Example #7
0
def _pages_from_json(request, offering, data):
    with django.db.transaction.atomic():
        try:
            data = data.decode('utf-8-sig')
        except UnicodeDecodeError:
            raise ValidationError("Bad UTF-8 data in file.")
            
        try:
            data = json.loads(data)
        except ValueError as e:
            raise ValidationError('JSON decoding error.  Exception was: "' + str(e) + '"')
        
        if not isinstance(data, dict):
            raise ValidationError('Outer JSON data structure must be an object.')
        if 'userid' not in data or 'token' not in data:
            raise ValidationError('Outer JSON data object must contain keys "userid" and "token".')
        if 'pages' not in data:
            raise ValidationError('Outer JSON data object must contain keys "pages".')
        if not isinstance(data['pages'], list):
            raise ValidationError('Value for "pages" must be a list.')
        
        try:
            user = Person.objects.get(userid=data['userid'])
            member = Member.objects.exclude(role='DROP').get(person=user, offering=offering)
        except (Person.DoesNotExist, Member.DoesNotExist):
            raise ValidationError('Person with that userid does not exist.')
        
        if 'pages-token' not in user.config or user.config['pages-token'] != data['token']:
            e = ValidationError('Could not validate authentication token.')
            e.status = 403
            raise e
        
        # if we get this far, the user is authenticated and we can start processing the pages...
        
        for i, pdata in enumerate(data['pages']):
            if not isinstance(pdata, dict):
                raise ValidationError('Page #%i entry structure must be an object.' % (i))
            if 'label' not in pdata:
                raise ValidationError('Page #%i entry does not have a "label".' % (i))
            
            # handle changes to the Page object
            pages = Page.objects.filter(offering=offering, label=pdata['label'])
            if pages:
                page = pages[0]
                old_ver = page.current_version()
            else:
                page = Page(offering=offering, label=pdata['label'])
                old_ver = None

            # check write permissions
            
            # mock the request object enough to satisfy _check_allowed()
            class FakeRequest(object):
                is_authenticated = True
            fake_request = FakeRequest()
            fake_request.user = FakeRequest()
            fake_request.user.username = user.userid

            if old_ver:
                m = _check_allowed(fake_request, offering, page.can_write, page.editdate())
            else:
                m = _check_allowed(fake_request, offering, offering.page_creators())
            if not m:
                raise ValidationError('You can\'t edit page #%i.' % (i))
            
            # handle Page attributes
            if 'can_read' in pdata:
                if type(pdata['can_read']) != str or pdata['can_read'] not in ACL_DESC:
                    raise ValidationError('Page #%i "can_read" value must be one of %s.'
                                          % (i, ','.join(list(ACL_DESC.keys()))))
                
                page.can_read = pdata['can_read']

            if 'can_write' in pdata:
                if type(pdata['can_write']) != str or pdata['can_write'] not in WRITE_ACL_DESC:
                    raise ValidationError('Page #%i "can_write" value must be one of %s.'
                                          % (i, ','.join(list(WRITE_ACL_DESC.keys()))))
                if m.role == 'STUD':
                    raise ValidationError('Page #%i: students can\'t change can_write value.' % (i))
                page.can_write = pdata['can_write']
            
            if 'new_label' in pdata:
                if type(pdata['new_label']) != str:
                    raise ValidationError('Page #%i "new_label" value must be a string.' % (i))
                if m.role == 'STUD':
                    raise ValidationError('Page #%i: students can\'t change label value.' % (i))
                if Page.objects.filter(offering=offering, label=pdata['new_label']):
                    raise ValidationError('Page #%i: there is already a page with that "new_label".' % (i))

                page.label = pdata['new_label']

            page.save()

            # handle PageVersion changes
            ver = PageVersion(page=page, editor=member)
            
            if 'title' in pdata:
                if type(pdata['title']) != str:
                    raise ValidationError('Page #%i "title" value must be a string.' % (i))
                
                ver.title = pdata['title']
            elif old_ver:
                ver.title = old_ver.title
            else:
                raise ValidationError('Page #%i has no "title" for new page.' % (i))

            if 'comment' in pdata:
                if type(pdata['comment']) != str:
                    raise ValidationError('Page #%i "comment" value must be a string.' % (i))
                
                ver.comment = pdata['comment']

            if 'use_math' in pdata:
                if type(pdata['use_math']) != bool:
                    raise ValidationError('Page #%i "comment" value must be a boolean.' % (i))

                ver.set_math(pdata['use_math'])

            if 'markup' in pdata:
                if isinstance(pdata['markup'], str):
                    raise ValidationError('Page #%i "markup" value must be a string.' % (i))

                ver.set_markup(pdata['markup'])

            if 'wikitext-base64' in pdata:
                if type(pdata['wikitext-base64']) != str:
                    raise ValidationError('Page #%i "wikitext-base64" value must be a string.' % (i))
                try:
                    wikitext = base64.b64decode(pdata['wikitext-base64']).decode('utf8')
                except TypeError:
                    raise ValidationError('Page #%i "wikitext-base64" contains bad base BASE64 data.' % (i))
                
                ver.wikitext = wikitext
            elif 'wikitext' in pdata:
                if type(pdata['wikitext']) != str:
                    raise ValidationError('Page #%i "wikitext" value must be a string.' % (i))
                
                ver.wikitext = pdata['wikitext']
            elif old_ver:
                ver.wikitext = old_ver.wikitext
            else:
                raise ValidationError('Page #%i has no wikitext for new page.' % (i))

            ver.save()
        
        return user