initial commit

This commit is contained in:
Faraphel 2024-05-14 21:56:21 +02:00
commit 9d6828d5ab
59 changed files with 910 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# Python
.venv/

8
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

33
.idea/SOME.iml Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="SOME/settings.py" />
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/TouYube" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/Witter" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/TouYube/apps/TouYube/templates" />
<option value="$MODULE_DIR$/Witter/apps/Witter/templates" />
</list>
</option>
</component>
</module>

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11 (SOME)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (SOME)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/SOME.iml" filepath="$PROJECT_DIR$/.idea/SOME.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

15
.idea/webResources.xml Normal file
View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebResourcesPaths">
<contentEntries>
<entry url="file://$PROJECT_DIR$">
<entryData>
<resourceRoots>
<path value="file://$PROJECT_DIR$/TouYube/apps/TouYube/static" />
<path value="file://$PROJECT_DIR$/Witter/apps/Witter/static" />
</resourceRoots>
</entryData>
</entry>
</contentEntries>
</component>
</project>

4
TouYube/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# Django
.static/
.media/
db.sqlite3

5
TouYube/README.md Normal file
View file

@ -0,0 +1,5 @@
# TouYube
This is an example website that host video.
The point of this website is to demonstrate SOME attack that exploit a CORS vulnerability.
CORS configuration can be edited in the `configuration/settings.py` file at the "ENABLE_CROSS_ORIGIN_SECURITY" settings.

0
TouYube/__init__.py Normal file
View file

View file

View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class TouyubeConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.TouYube'

View file

@ -0,0 +1,19 @@
from django import forms
class LoginForm(forms.Form):
"""
A form to login
"""
username = forms.CharField(max_length=32)
password = forms.CharField(widget=forms.PasswordInput())
class UploadForm(forms.Form):
"""
A form to upload a video
"""
name = forms.CharField(max_length=128)
content = forms.FileField()

View file

@ -0,0 +1,27 @@
# Generated by Django 5.0.6 on 2024-05-14 18:08
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Video',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128)),
('content', models.FileField(upload_to='videos/')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='videos', to=settings.AUTH_USER_MODEL)),
],
),
]

View file

@ -0,0 +1,16 @@
import uuid
from django.contrib.auth import get_user_model
from django.db import models
class Video(models.Model):
"""
Represent a video.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=128)
author = models.ForeignKey(to=get_user_model(), on_delete=models.CASCADE, related_name="videos")
content = models.FileField(upload_to=f"videos/")

View file

@ -0,0 +1,3 @@
body {
margin: 0;
}

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<meta charset="UTF-8">
<title>{% block title %}TouYube{% endblock %}</title>
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

View file

@ -0,0 +1,9 @@
<nav>
<button><a href="{% url 'homepage' %}">Homepage</a></button>
{% if request.user.is_authenticated %}
<button><a href="{% url 'video_upload' %}">Upload</a></button>
<button><a href="{% url 'logout' %}">Logout</a></button>
{% else %}
<button><a href="{% url 'login' %}">Login</a></button>
{% endif %}
</nav>

View file

@ -0,0 +1,16 @@
{% extends "TouYube/base/base.html" %}
{% block title %}{{ block.super }} - Homepage{% endblock %}
{% block body %}
{% include "TouYube/base/navigation.html" %}
<h1>Homepage</h1>
{# go through all the videos #}
{% for video in videos %}
{# show the video #}
<div>
<a href="{% url 'video_full' video.id %}"><b>{{ video.name }}</b> - {{ video.author }}</a>
</div>
{% endfor %}
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "TouYube/base/base.html" %}
{% block title %}{{ block.super }} - Login{% endblock %}
{% block body %}
{% include "TouYube/base/navigation.html" %}
<form method="POST">
{% csrf_token %}
{{ form_login }}
<input type="submit" value="Login" />
</form>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "TouYube/base/base.html" %}
{% block title %}{{ block.super }} - Upload{% endblock %}
{% block body %}
{% include "TouYube/base/navigation.html" %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form_upload }}
<input type="submit" value="Upload" />
</form>
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends "TouYube/base/base.html" %}
{% load static %}
{% block head %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'TouYube/embed.css' %}" />
{% endblock %}
{% block title %}{{ block.super }} - Video {{ video.name }}{% endblock %}
{% block body %}
<video controls width="100%" height="100%">
<source src="{{ video.content.url }}" type="video/mp4"/>
</video>
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends "TouYube/base/base.html" %}
{% block title %}{{ block.super }} - Video {{ video.name }}{% endblock %}
{% block body %}
{% include "TouYube/base/navigation.html" %}
<h1>{{ video.name }}</h1>
<h2>{{ video.author }}</h2>
<video controls width="500">
<source src="{{ video.content.url }}" type="video/mp4"/>
</video>
{% if request.user == video.author %}
<button><a href="{% url 'video_delete' video.id %}">Delete</a></button>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

View file

@ -0,0 +1,132 @@
from uuid import UUID
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import render, redirect, get_object_or_404
from apps.TouYube import forms, models
def view_homepage(request: WSGIRequest) -> HttpResponse:
videos = models.Video.objects.all()
return render(
request,
"TouYube/homepage.html",
dict(videos=videos)
)
def view_login(request: WSGIRequest) -> HttpResponse:
"""
Login to the website
"""
form_login = forms.LoginForm(request.POST)
if form_login.is_valid():
# try to authenticate the user
user = authenticate(
request,
username=form_login.cleaned_data["username"],
password=form_login.cleaned_data["password"],
)
# if authenticated, log him persistently
if user is not None:
login(request, user)
return redirect("homepage")
# otherwise add an error to the form
form_login.add_error("password", "invalid credentials")
return render(
request,
"TouYube/login.html",
dict(form_login=form_login)
)
def view_logout(request: WSGIRequest) -> HttpResponse:
"""
Logout from the website
"""
logout(request)
return redirect("homepage")
@login_required
def view_video_upload(request: WSGIRequest) -> HttpResponse:
"""
The page to upload a file
"""
form_upload = forms.UploadForm(request.POST, request.FILES)
if form_upload.is_valid():
# save the video
video = models.Video.objects.create(
author=request.user,
name=form_upload.cleaned_data["name"],
content=form_upload.cleaned_data["content"]
)
video.save()
# redirect the user to his own video
return redirect("video_full", video.id)
return render(
request,
"TouYube/upload.html",
dict(form_upload=form_upload)
)
@login_required
def view_video_delete(request: WSGIRequest, video_id: UUID) -> HttpResponse:
"""
Delete a video
"""
video = get_object_or_404(models.Video, id=video_id)
# check if the user is the video's author
if request.user != video.author:
return HttpResponseForbidden()
# delete the video
video.delete()
return redirect("homepage")
def view_video_full(request: WSGIRequest, video_id: UUID) -> HttpResponse:
"""
Render the page for a video
"""
video = get_object_or_404(models.Video, id=video_id)
return render(
request,
"TouYube/video_full.html",
dict(video=video)
)
def view_video_embed(request: WSGIRequest, video_id: UUID) -> HttpResponse:
"""
Render the page for an embedded video
"""
video = get_object_or_404(models.Video, id=video_id)
return render(
request,
"TouYube/video_embed.html",
dict(video=video)
)

0
TouYube/apps/__init__.py Normal file
View file

View file

View file

@ -0,0 +1,16 @@
"""
ASGI config for configuration project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
application = get_asgi_application()

View file

@ -0,0 +1,149 @@
"""
Django settings for configuration project.
Generated by 'django-admin startproject' using Django 5.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-87uz=bnd&m+$(!qfzs3$bum)!e6pw$8gaw_^cehmuyuft5q4!#'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ENABLE_CROSS_ORIGIN_SECURITY = False
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
*(("corsheaders",) if ENABLE_CROSS_ORIGIN_SECURITY else ()),
'apps.TouYube',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
*(("corsheaders.middleware.CorsMiddleware",) if ENABLE_CROSS_ORIGIN_SECURITY else ()),
"django.middleware.common.CommonMiddleware",
*(('django.middleware.csrf.CsrfViewMiddleware') if ENABLE_CROSS_ORIGIN_SECURITY else ()),
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
*(('django.middleware.clickjacking.XFrameOptionsMiddleware',) if ENABLE_CROSS_ORIGIN_SECURITY else ()),
]
ROOT_URLCONF = 'configuration.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
},
},
]
WSGI_APPLICATION = 'configuration.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = ".static"
# Media files
MEDIA_URL = "media/"
MEDIA_ROOT = ".media"
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# CORS Settings
# https://pypi.org/project/django-cors-headers/
# CORS_ALLOWED_ORIGINS: list[str] = []
# CORS_ALLOW_ALL_ORIGINS: bool = True
if not ENABLE_CROSS_ORIGIN_SECURITY:
X_FRAME_OPTIONS = 'ALLOWALL'
# Login Settings
LOGIN_URL: str = "login/"

View file

@ -0,0 +1,38 @@
"""
URL configuration for configuration project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
import apps.TouYube.views
from configuration import settings
urlpatterns = [
path('', apps.TouYube.views.view_homepage, name="homepage"),
path('login/', apps.TouYube.views.view_login, name="login"),
path('logout/', apps.TouYube.views.view_logout, name="logout"),
path('video/upload/', apps.TouYube.views.view_video_upload, name="video_upload"),
path('video/delete/<uuid:video_id>/', apps.TouYube.views.view_video_delete, name="video_delete"),
path('video/view/<uuid:video_id>/', apps.TouYube.views.view_video_full, name="video_full"),
path('video/embed/<uuid:video_id>/', apps.TouYube.views.view_video_embed, name="video_embed"),
path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -0,0 +1,16 @@
"""
WSGI config for configuration project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
application = get_wsgi_application()

22
TouYube/manage.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

2
TouYube/requirements.txt Normal file
View file

@ -0,0 +1,2 @@
django
django-cors-headers

3
Witter/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Django
db.sqlite3

3
Witter/README.md Normal file
View file

@ -0,0 +1,3 @@
# Witter
This is an example website that will embed video maliciously.
The point of this website is to demonstrate SOME attack that exploit a CORS vulnerability.

0
Witter/__init__.py Normal file
View file

View file

View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class WitterConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.Witter'

View file

@ -0,0 +1 @@
from django import forms

View file

@ -0,0 +1 @@
from django.db import models

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<meta charset="UTF-8">
<title>{% block title %}Witter{% endblock %}</title>
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

View file

@ -0,0 +1,10 @@
{% extends "Witter/base/base.html" %}
{% block title %}{{ block.super }} - Homepage{% endblock %}
{% block body %}
<h1>Homepage</h1>
<a href="http://localhost:8080/video/delete/9cf5f8e6-9333-41de-a913-f4ec2e698a9d/">
Je suis un bouton qui ne va sûrement pas supprimer ta vidéo préférée 😊
</a>
{% endblock %}

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

View file

@ -0,0 +1,12 @@
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse
from django.shortcuts import render
from apps.Witter import forms, models
def view_homepage(request: WSGIRequest) -> HttpResponse:
return render(
request,
"Witter/homepage.html",
)

0
Witter/apps/__init__.py Normal file
View file

View file

View file

@ -0,0 +1,16 @@
"""
ASGI config for configuration project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
application = get_asgi_application()

View file

@ -0,0 +1,129 @@
"""
Django settings for configuration project.
Generated by 'django-admin startproject' using Django 5.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-8p^3+c8q#t1i@8do06^#+%lr&*n8474!d_tp4%zua+7!^qw2jj'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'apps.Witter',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'configuration.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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',
],
},
},
]
WSGI_APPLICATION = 'configuration.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = ".static"
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

View file

@ -0,0 +1,31 @@
"""
URL configuration for configuration project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
import apps.Witter.views
from configuration import settings
urlpatterns = [
path('', apps.Witter.views.view_homepage, name="homepage"),
path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

View file

@ -0,0 +1,16 @@
"""
WSGI config for configuration project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
application = get_wsgi_application()

22
Witter/manage.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configuration.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

2
Witter/requirements.txt Normal file
View file

@ -0,0 +1,2 @@
django
django-cors-headers