2016-03-22 7 views
2

Ich möchte Benutzer in der Lage sein, hochladen ihre benutzerdefinierten HTML-Vorlagen einschließlich CSS-Styling und PNG-und JPEG-Bilder. Diese HTML-Dateien sollen über Django abrufbar sein. Das bedeutet, dass sie den resultierenden HTML-Inhalt in Form einer normalen Webseite sehen können. Um das zu können, muss ich (scheinbar, kenne keinen besseren Ansatz) die HTML-Dateien in das Template-Verzeichnis hochladen.Laden Sie benutzerdefinierte Vorlagen in Django

Das ist mein aktuelles Modell:

class StylesheetFile(models.Model): 
    HTML = 'HTML' 
    CSS = 'CSS' 
    JPEG = 'JPEG' 
    PNG = 'PNG' 

    # Currently supported mimetypes 
    MIMETYPE_CHOICES = (
     (HTML, 'text/html'), 
     (CSS , 'text/css' ), 
     (JPEG, 'image/jpeg'), 
     (PNG , 'image/png'), 
    ) 

    mimetype = models.CharField(max_length=64, choices = MIMETYPE_CHOICES) 
    company = models.ForeignKey(Company) 
    file = models.FileField(upload_to=get_upload_path) 

Und dies ist die aktuelle Funktion die upload_path zu bestimmen:

def get_upload_path(instance, filename): 
    if instance.mimetype == 'HTML': 
     return os.path.join(
      settings.TEMPLATES[0]['DIRS'][1], 
      instance.company.name, 
      filename) 
    if instance.mimetype == 'CSS': 
     return os.path.join(
      "custom_css", 
      instance.company.name, 
      filename) 
    if instance.mimetype == 'JPEG' or instance.mimetype == 'PNG': 
     return os.path.join(
      "custom_img", 
      instance.company.name, 
      filename) 

Vorlageneinstellungen

TEMPLATES = [ 
    { 
     'BACKEND': 'django.template.backends.django.DjangoTemplates', 
     'DIRS': [ 
      '/home/ubuntu/app/templates/', 
      '/home/ubuntu/app/custom_templates', 
     ], 
     'APP_DIRS': True, 
     'OPTIONS': { 
      'context_processors': [ 
       'django.template.context_processors.debug', 
       'django.template.context_processors.request', 
       'django.contrib.auth.context_processors.auth', 
       'django.contrib.messages.context_processors.messages', 
      ], 
     }, 
    }, 
] 

Als ich das das CSS tun stylings, png und jpeg Dateien werden korrekt hochgeladen, aber die html Dateien nicht. Ich erhalte folgenden Fehler:

The joined path (/home/ubuntu/app/custom_templates/FooCompany/factors.html) is located outside of the base path component (/home/ubuntu/app/static/media) 

Was kann ich tun, um diesen Fehler zu vermeiden? Gibt es eine Best-Practice-Herangehensweise an mein Problem oder muss ich einen Workaround wie die Einstellung eines von m TEMPLATE_DIRS auf /home/ubuntu/app/static/media/custom_templates. Vielleicht ist das nicht einmal ein Workaround und legitime Praxis .. Ich weiß es nicht wirklich wissen .. Hilfe wird sehr geschätzt!

Antwort

4

Sie können FileField nicht zum Hochladen von Dateien außerhalb von MEDIA_ROOT verwenden. Das ist eine wichtige Sicherheitsmaßnahme.

Sie könnten TEMPLATE_DIRS auf etwas innerhalb MEDIA_ROOT setzen und höchstwahrscheinlich würde dies funktionieren, aber das macht mein Zucken wirklich schwer. Das würde den Benutzern im Wesentlichen die Möglichkeit geben, beliebige Vorlage für jede Seite auf der Website zu überschreiben.

Sie müssen diese Vorlagen nicht als HTML-Dateien speichern, um sie als Django-Vorlagen zu verwenden. Sie können sie in einer Datenbank speichern und sie von String direkt machen:

from django.template import engines 
from django.http import HttpResponse 

# Get the template from database 
template_from_db = YourCustomTemplateModel.objects.get(name='homepage') 
template_string = template_from_db.content 

# Create a django Template object 
template = engines['django'].from_string(template_string) 

# Render the template to a string 
context = {'foo': 'bar'} 
page_content = template.render(context=context) 

# Send page to a the browser 
return HttpResponse(page_content) 

Sie sollten jedoch denken wirklich schwer über die Auswirkungen auf die Sicherheit dieser im Allgemeinen zu tun. Sind Sie wirklich zufrieden damit, dass Template-Ersteller in der Lage sind, beliebiges JavaScript auf Ihrer Domain zu setzen (denken Sie Cross-Site Scripting Schwachstelle)? Wie wäre es mit dem Aufruf von beliebigen Methoden (oder zumindest solchen, die keine Argumente haben) und dem Zugriff auf beliebige Argumente für Objekte, die Sie im context Wörterbuch übergeben?

+0

Zunächst einmal vielen Dank für Ihre Antwort! Ich habe bereits über die Sicherheitsprobleme nachgedacht, aber mein Vorgesetzter hat mir gesagt, ich solle eine Funktion schreiben, um nach Javascript zu suchen und es nicht zuzulassen (ich hoffe, das ist so einfach wie es klingt). Der Benutzer darf also grundsätzlich nur HTML css und jpg und png hochladen. Kein JavaScript überhaupt –

+0

Das Entfernen von JavaScript ist überhaupt nicht einfach. Nicht auf eine sichere Weise, die nicht von einem cleveren Angreifer umgangen werden kann. Eigentlich ist das ein wirklich hartes Problem. –

+0

JS ist nicht das einzige Problem. Sie können Abfragen in einer Vorlage ausführen und Datenbankverbindungen überfluten oder vertrauliche Daten abrufen. Was ist mit '{% für Freund in user.friends%} {{friend.password}} {{friend.email}} {% endfor%}' oder '{% für a in user.friends%} {% für b in a.friends%} {% für c in b.friends%} {% endfor%} {% endfor%} {% endfor%} ' –