django-phpBB3

Django, Flask, Bottle, WSGI, CGI…
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Warum wird da irgendwelches HTML geparsed?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das passiert im code Teil von DjangoBB beim speichern eines neuen Beitragt:

Code: Alles auswählen

class Post(models.Model):
...
    def save(self, *args, **kwargs):
        self.body_html = convert_text_to_html(self.body, self.markup)
        if forum_settings.SMILES_SUPPORT and self.user.forum_profile.show_smilies:
            self.body_html = smiles(self.body_html)
        super(Post, self).save(*args, **kwargs)
Bei DjangoBB wird einmal der Text eines Beitrags als "roh"-Markup und einmal als gerenderter HTML-Code gespeichert.

Die SMILES_SUPPORT ist der Übeltäter. Im Grunde werden Text Smilies durch Bilder ersetzt.
Wenn ich https://github.com/slav0nic/DjangoBB/bl ... um/util.py richtig verstanden hab, wird HTMLParser genutzt um Smilies nicht in 'a', 'pre' und 'span' Bereiche zu ersetzten.

HTMLParser hat ein paar Probleme, wenn der HTML nicht ganz sauber ist. Ich konnte allerdings den Fehler lokal nicht reproduzieren.

Frage mich nun, ob man in DjangoBB eine andere Lösung suchen sollte: Kann man dort überhaupt diesen Fehler provozieren? Oder kann man nur in phpBB "defekten" HTML code über bbcode produzieren.
Vielleicht liegt der Fehler auch in der postmarkup Bibliothek.

EDIT: Bei meiner DjangoBB installation konnte ich keinen Fehler Provozieren: http://www.pylucid.org/de/forum/topic/356/
Den Migrationstest hatte ich allerdings auch mit Python 2.6.6 gemacht (Wobei die letzte 2.6.x Release ist 2.6.8). Auf meinem Server läuft 2.7.3
Evtl. liegt es an einer älteren Version von HTMLParser. Auf http://bugs.python.org/issue findet man einige Einträge, wenn man einfach nach "HTMLParser" sucht...
Vielleicht sollte man einfach HTMLParseError abfangen wenn settings.DEBUG==False und die Smilies einfach als Text belassen.
Eigentlich ist es eh ein wenig Blöd, wenn man die Pfade Hardcoded. Man müsste eine Migration machen, wenn man die URL der statischen Dateien ändert.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Das passiert im code Teil von DjangoBB beim speichern eines neuen Beitragt:

Code: Alles auswählen

class Post(models.Model):
...
    def save(self, *args, **kwargs):
        self.body_html = convert_text_to_html(self.body, self.markup)
        if forum_settings.SMILES_SUPPORT and self.user.forum_profile.show_smilies:
            self.body_html = smiles(self.body_html)
        super(Post, self).save(*args, **kwargs)
Bei DjangoBB wird einmal der Text eines Beitrags als "roh"-Markup und einmal als gerenderter HTML-Code gespeichert.
Ok, und warum ist da HTML? Mir kommt das nicht vor als wäre das eine gute Idee, in der Datenbank irgendwelches HTML abzulegen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich hab's. Es liegt am HTMLParser von 2.6... In 2.7 ist alles ok.

Hier ein paar Tests:

[url="foo"bar"]one foo"bar :)[/url] A"B :D
[url="foo".bar"]two foo".bar :)[/url] A".B :D
[url="foo."bar"]three foo."bar :)[/url] A."B :D
[url="foo.".bar"]four foo.".bar :)[/url] A.".B :D

Hiermit kann man es nachvollziehen:

Code: Alles auswählen

import sys
from HTMLParser import HTMLParser

print sys.version

tests=(
	'<a href="foo"bar"></a>',
	'<a href="foo".bar"></a>',
	'<a href="foo."bar"></a>',
	'<a href="foo.".bar"></a>',
)

for html in tests:
	print
	print repr(html)
	parser = HTMLParser()
	try:
		parser.feed(html)
		parser.close()
	except Exception, err:
		print "Error: %s" % err
	else:
		print "OK"

print "--END--"
Ausgabe 1:

Code: Alles auswählen

2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3]

'<a href="foo"bar"></a>'
OK

'<a href="foo".bar"></a>'
OK

'<a href="foo."bar"></a>'
OK

'<a href="foo.".bar"></a>'
OK
--END--
Ausgabe 2:

Code: Alles auswählen

2.6.6 (r266:84292, Sep 11 2012, 08:34:23) 
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)]

'<a href="foo"bar"></a>'
Error: EOF in middle of construct, at line 1, column 1

'<a href="foo".bar"></a>'
Error: malformed start tag, at line 1, column 14

'<a href="foo."bar"></a>'
Error: EOF in middle of construct, at line 1, column 1

'<a href="foo.".bar"></a>'
Error: malformed start tag, at line 1, column 15
--END--

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat geschrieben:Ok, und warum ist da HTML? Mir kommt das nicht vor als wäre das eine gute Idee, in der Datenbank irgendwelches HTML abzulegen.
Das ist ein anderes Thema ;)

Es ist halt eine einfache Form eines Caches. Ansonsten müsste man immer on-the-fly markup -> html erzeugen. Kann man natürlich auch. Würde aber den Server stärker belasten.

Den einzigen Knackpunkt den ich hier sehe, wäre das mit dem ändern der Smilies. Aber eine migration in diesem Falle wäre einfach:

Code: Alles auswählen

for post in Post.objects.all():
    post.save()

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:
Leonidas hat geschrieben:Ok, und warum ist da HTML? Mir kommt das nicht vor als wäre das eine gute Idee, in der Datenbank irgendwelches HTML abzulegen.
Das ist ein anderes Thema ;)

Es ist halt eine einfache Form eines Caches. Ansonsten müsste man immer on-the-fly markup -> html erzeugen. Kann man natürlich auch. Würde aber den Server stärker belasten.
Das ist ein ziemlich schlechter Cache, weil man sich damit gleich Möglichkeiten zu permanenten XSS aufmacht und die Serverbelastung müsste man eh erstmal beobachten ("premature optimization...") und wenn die sich als schwachpunkt erweist, dann einen richtigen Cache verwenden.

Zudem bekommt man Probleme wenn man das HTML anders rendern will, etwa für print-Vorschau oder generell bei Änderungen des gewünschten Ausgabeformats. Anti-Feature, finde ich, würde ich rausnehmen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

XSS sollte so oder so nicht möglich sein. Also mit dem cachen von HTML und ohne. Falls eine XSS Lücke auftauchen würde, sollte man natürlich daran denken, das der HTML code gecachet ist ;)

Andere Ausgabeformate? Es ist ja nur der Nackte Beitrags-Text. Wie sollte man markup wie codebb, markdown anders als HTML Ausgeben?

Warum das Ursprünglich so gemacht wurde, kann ich allerdings nicht sagen. Es auch caching Gründen zu machen erscheint mir aber naheliegend. Denke das kommt noch von Punbb, auf dem DjangoBB beruht.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:XSS sollte so oder so nicht möglich sein. Also mit dem cachen von HTML und ohne. Falls eine XSS Lücke auftauchen würde, sollte man natürlich daran denken, das der HTML code gecachet ist ;)
Oder eben nicht cachen. Verschwendet nur Speicher in der Datenbank und hält Daten unnötig redundant in zwei Formaten vor. Für Caching gibts ja genug Lösungen, die die Einträge auch auslaufen lassen, Memcached und Riak fallen mir da spontan ein, die Lösen beide das Rendering-"Problem" deutlich effizienter.

HTML in der Datenbank gefällt mir generell nicht, aber wer weiß, vielleicht stehe ich damit alleine dar?
jens hat geschrieben:Andere Ausgabeformate? Es ist ja nur der Nackte Beitrags-Text. Wie sollte man markup wie codebb, markdown anders als HTML Ausgeben?
Andere Ausgabeformate wie naheliegendes Atom/RSS, eine Print/Archiv-Ansicht wie viele Forensysteme das machen, Beitragszusammenfassung per E-Mail (mich stört das in phpBB, dass da nicht steht was denn exakt gepostet wurde, wenn ich Benachrichtigt werde). Könnte mir auch PDF denken, aber gut, das ist vielleicht etwas zu viel des guten.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also das überzeugt mich jetzt nicht so ganz.

Das einzige was ich zählen würde wäre:
* Änderung der STATIC_URL
* Speicherverbrauch in DB

Bei "Atom/RSS, eine Print/Archiv-Ansicht" würde man doch auch den HTML Code nehmen. Aber wäre auch egal. denn die Ursprüngliche markup Version bleibt ja auch in der DB. Also selbst wenn man auf diese zurückgreifen wollen würde, könnte man das tun. Aber ich denke auch für eine Plain-Text Zusammenfassung sollte man lieber die HTML Version nehmen und die Tags entfernen. Denn es gibt ja neben codebb auch markdown und ich will noch creole dazu packen. So müsste man von allen einen zusätzlichen Konverter schreiben.

Caching mit Memcached und Co. schön und gut. Aber IMHO eher für andere Dinge, die dynamischer sind, Sinnvoll. z.B. wird bei der aktuellen Variante der cache nie leer. Oft updaten muß man auch nicht. Ich denke effektiver kann man das nicht gestalten.
Natürlich kann man es auch komplett ohne Cache betreiben. Welchen Anteil das HTML-Generieren am gesamten ausmacht, weiß ich nicht, wäre interessant zu untersuchen. Denke aber schon, das es spürbar was ausmacht.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ach, der HTMLParser wurde anscheinend in 2.7.3 verbessert. Denn mit 2.7.2 sieht es auch so aus, wie mit 2.6:

Code: Alles auswählen

2.7.2 (default, Jun 24 2011, 12:21:10) [MSC v.1500 32 bit (Intel)]

'<a href="foo"bar"></a>'
HTMLParseError: EOF in middle of construct, at line 1, column 1

'<a href="foo".bar"></a>'
HTMLParseError: malformed start tag, at line 1, column 14

'<a href="foo."bar"></a>'
HTMLParseError: EOF in middle of construct, at line 1, column 1

'<a href="foo.".bar"></a>'
HTMLParseError: malformed start tag, at line 1, column 15
--END--
EDIT: In Python 2.7.3 wurden einige Fehler in HTMLParser behoben:
- HTMLParser is now able to handle slashes in the start tag.
- Issue #13987: HTMLParser is now able to handle EOFs in the middle of a construct and malformed start tags.
- Issue #13993: HTMLParser is now able to handle broken end tags.
- Issue #13993: HTMLParser is now able to handle broken end tags.
- Issue #13358: HTMLParser now calls handle_data only once for each CDATA.
- Issues #1745761, #755670, #13357, #12629, #1200313: HTMLParser now correctly handles non-valid attributes, including adjacent and unquoted attributes.
- Issue #670664: Fix HTMLParser to correctly handle the content of ``<script>...</script>`` and ``<style>...</style>``.
- Issue #7311: Fix HTMLParser to accept non-ASCII attribute values.
- Patch #912410: Replace HTML entity references for attribute values in HTMLParser.
Siehe: http://hg.python.org/cpython/file/d46c1 ... /Misc/NEWS

Hab es in der README geschrieben: https://github.com/jedie/django-phpBB3#troubleshooting und es in DjangoBB angesprochen: http://support.djangobb.org/topic/349/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nächstes TODO für dir Migration: Forum Rechte umsetzten. Wobei ich erstmal wissen müßte wie phpBB die Rechte hinterlegt. Zumindest hab ich es nun in der README erwähnt...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

jens hat geschrieben:Ach, der HTMLParser wurde anscheinend in 2.7.3 verbessert. Denn mit 2.7.2 sieht es auch so aus, wie mit 2.6:
Die Django Patches für unseren HTMLParser-Wrapper sind mit Python 2.7.4 wieder kaputt gegangen (oder wars 2.7.4+, kA), da gabs also noch einige weitere Änderungen ;)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Keine Ahnung. Auf jeden Fall fange ich einen Fehler ab und dann werden halt smilies nicht ersetzt. IMHO besser als das der User einen 500 bekommt.

Was anderes: Passwörter von den alten phpBB Usern übernehmen:

z.Z. setzte ich einfach kein Passwort, bzw einen leeren String. Das ist schon mal dumm, weil es zu dem kommen kann:
ValueError: Unknown password hashing algorithm ''. Did you specify it in the PASSWORD_HASHERS setting?
Ich vermute mal ich sollte besser None statt "" setzten.

Allerdings Frage ich mich, ob man das nicht noch besser hin bekommt. So das der User nicht aktiv ein Passwort reset ausführen muß. Mir schwebt gerade vor, das ich beim ersten Login das alte phpBB3 Passwort nehme, zum Einloggen, dann aber das Plain-Text-Passwort nutzte, um den Hash von phpBB auf Django umzustellen.
Wie der phpBB3 hash funktioniert, ist anscheinend bei https://github.com/japsu/phpbb-python/b ... nctions.py implementiert.

Was meint ihr?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Du machst einfach folgendes: Übernimm die alten Passwörter und prefixe sie mit "jenshash$". Dann schreibst du für Django einen Password-Hasher: https://docs.djangoproject.com/en/dev/t ... -passwords Als algorithm gibst du dann eben "jenshash" an und fügst den in PASSWORD_HASHERS am Ende (bzw nach 'django.contrib.auth.hashers.PBKDF2PasswordHasher') hinzu. Mit dem nächsten Login eines Users wird sein Passwort automatisch upgegradet...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ganz genau.

Schon fertig: https://github.com/jedie/django-phpBB3/ ... 7c94988774

DocTests / Unittests funktionieren schon. In der Praxis muß ich es aber noch testen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

In der Praxis kann man es nun bei http://jedie.lynx.uberspace.de/forum/ testen. Denn ich hab dort alle Passwörter mit ./manage.py phpbb2djangobb --only_users übernommen ;)
Siehe: http://www.python-forum.de/viewtopic.ph ... 33#p228633

Zu django-phpBB3: Vielleicht ist es keine gute Idee, den pseudo User "Anonymous" als aktiv zu kennzeichnen. Der hat zwar kein gültiges Passwort und keine email Adresse, aber dennoch sollte ich das mal ändern.
EDIT: Blödsinn, hab ich ja so gemacht: https://github.com/jedie/django-phpBB3/ ... bb.py#L505 ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten