Merge branch 'master' into production
This commit is contained in:
commit
8a63661800
13 changed files with 251 additions and 6 deletions
|
|
@ -10,6 +10,7 @@ from django.shortcuts import render, redirect
|
|||
from blog.models import Topic, Tag, Blogpost
|
||||
from django.template import Template, Context
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django_2fa.decorators import mfa_login_required
|
||||
|
||||
|
||||
def render_md_file(path) -> Template:
|
||||
|
|
@ -53,6 +54,7 @@ def index(request) -> HttpResponse:
|
|||
|
||||
|
||||
@login_required
|
||||
@mfa_login_required
|
||||
def edit(request, id) -> HttpResponse:
|
||||
blogpost = Blogpost.objects.get(pk=id)
|
||||
mdfile_content = open(blogpost.mdfile, "r").read()
|
||||
|
|
@ -94,6 +96,7 @@ def edit(request, id) -> HttpResponse:
|
|||
|
||||
@login_required
|
||||
@csrf_exempt
|
||||
@mfa_login_required
|
||||
def order(request) -> HttpResponse:
|
||||
if request.method == "POST":
|
||||
root_id = int(request.POST['rootID']) if request.POST['rootID'] != 'root_list' else None
|
||||
|
|
@ -114,6 +117,7 @@ def order(request) -> HttpResponse:
|
|||
|
||||
|
||||
@login_required
|
||||
@mfa_login_required
|
||||
def addpost(request) -> HttpResponse:
|
||||
context = {'alltopics': Topic.objects.all().order_by('name').values(), 'markdown': '',
|
||||
'roottopics': Topic.objects.all().filter(rootTopic=None),
|
||||
|
|
@ -154,6 +158,7 @@ def addpost(request) -> HttpResponse:
|
|||
|
||||
|
||||
# @login_required
|
||||
# @mfa_login_required
|
||||
# def createmocks(request, objtype, n) -> HttpResponse:
|
||||
# topics = TopicFactory.create_batch(n)
|
||||
#
|
||||
|
|
@ -171,6 +176,7 @@ def addpost(request) -> HttpResponse:
|
|||
|
||||
|
||||
@login_required
|
||||
@mfa_login_required
|
||||
def addtopic(request):
|
||||
context = {'roottopics': Topic.objects.all().filter(rootTopic=None), 'allposts': Blogpost.objects.all()}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ INSTALLED_APPS = [
|
|||
'blog',
|
||||
'markdownblog',
|
||||
'fontawesomefree',
|
||||
'django_2fa',
|
||||
'django_extensions',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
|
|
@ -48,6 +50,7 @@ MIDDLEWARE = [
|
|||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django_2fa.middleware.MFAProctectMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'markdownblog.urls'
|
||||
|
|
@ -129,9 +132,21 @@ STATIC_ROOT = '/markdownblog/static'
|
|||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
LOGIN_URL = '/accounts/login'
|
||||
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
LOGOUT_REDIRECT_URL = "/"
|
||||
|
||||
CSRF_HEADER_NAME = "X-CSRFToken"
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = ["https://cdaut.de", "http://cdaut.de"]
|
||||
|
||||
# multifactor auth
|
||||
MFA_URL = '/accounts/2fa/login'
|
||||
|
||||
SALT_KEY = os.environ['SALT_KEY']
|
||||
|
||||
MFA_ISSUER_NAME = 'MDBlog'
|
||||
|
||||
# Configure mail here
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
|
|
|||
|
|
@ -24,4 +24,8 @@ header, main, footer {
|
|||
header, main, footer {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mt-3 {
|
||||
margin-top: 3em;
|
||||
}
|
||||
57
markdownblog/markdownblog/templates/2fa/add-device.html
Normal file
57
markdownblog/markdownblog/templates/2fa/add-device.html
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{% extends 'base/base.html' %}
|
||||
{% load i18n static %}
|
||||
{% block title %}
|
||||
Add new 2FA device
|
||||
{% endblock %}
|
||||
{% block includehere %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col s12">
|
||||
<h3>{% translate 'Add new 2FA device' %}</h3>
|
||||
<hr>
|
||||
{% if form.errors and not form.non_field_errors %}
|
||||
<p class="errornote">
|
||||
{% if form.errors.items|length == 1 %}{% translate "Please correct the error below." %}{% else %}
|
||||
{% translate "Please correct the errors below." %}{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<form action="{{ request.path }}" method="post" id="add-device-form" class="col s12">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="{{ next_field }}" value="{{ next }}">
|
||||
{% if form.non_field_errors %}
|
||||
<div class="form-row">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="input-field col s12 l6">
|
||||
{{ form.name.errors }}
|
||||
{{ form.name }}
|
||||
{{ form.name.label_tag }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12 l6">
|
||||
{{ form.device_type.errors }}
|
||||
{{ form.device_type }}
|
||||
{{ form.device_type.label_tag }}
|
||||
</div>
|
||||
</div>
|
||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||
<div class="row">
|
||||
<div class="input-field col s12 l6">
|
||||
<button class="btn waves-effect waves-light" type="submit">
|
||||
{% translate 'Continue' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var elems = document.querySelectorAll('select');
|
||||
var instances = M.FormSelect.init(elems);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
41
markdownblog/markdownblog/templates/2fa/complete-fido.html
Normal file
41
markdownblog/markdownblog/templates/2fa/complete-fido.html
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{% extends "base/base.html" %}
|
||||
{% load i18n static %}
|
||||
{% block title %}{% translate "Complete setup for 2FA Device" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div id="content-main" class="col s12">
|
||||
<h3>{% translate 'Hardware Key Setup' %}</h3>
|
||||
<hr>
|
||||
<h4 class="tc">{% translate 'Insert your hardware key to complete setup for:' %} {{ device.name }}</h4>
|
||||
</div>
|
||||
<script
|
||||
src="{% static '2fa/axios.min.js' %}"></script>
|
||||
<script src="{% static '2fa/cbor.js' %}"></script>
|
||||
<script>
|
||||
function start_reg() {
|
||||
axios.post("{% url 'django_2fa:fido-reg-begin' device.id %}", {}, {responseType: 'arraybuffer'})
|
||||
.then((response) => {
|
||||
return CBOR.decode(response.data);
|
||||
})
|
||||
.then((options) => {
|
||||
return navigator.credentials.create(options);
|
||||
})
|
||||
.then((attestation) => {
|
||||
console.log(attestation);
|
||||
var data = CBOR.encode({
|
||||
"attestationObject": new Uint8Array(attestation.response.attestationObject),
|
||||
"clientDataJSON": new Uint8Array(attestation.response.clientDataJSON)
|
||||
});
|
||||
return axios.post("{% url 'django_2fa:fido-reg-complete' device.id %}", data, {});
|
||||
})
|
||||
.then((response) => {
|
||||
location.href = "{{ next }}";
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
alert('{% translate "Error in hardware key registration" %}');
|
||||
});
|
||||
}
|
||||
|
||||
start_reg();
|
||||
</script>
|
||||
{% endblock %}
|
||||
39
markdownblog/markdownblog/templates/2fa/devices.html
Normal file
39
markdownblog/markdownblog/templates/2fa/devices.html
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{% extends 'base/base.html' %}
|
||||
{% load i18n static %}
|
||||
{% block title %}
|
||||
Manage 2FA devices
|
||||
{% endblock %}
|
||||
{% block includehere %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="content-main" class="col s12">
|
||||
<h3>{% translate 'Manage 2FA devices' %}</h3>
|
||||
<hr>
|
||||
<a href="{% url 'django_2fa:device-add' %}" class="waves-effect waves-light btn mt-3">
|
||||
Add Device
|
||||
</a>
|
||||
<ul class="collection">
|
||||
{% for d in devices %}
|
||||
<li class="collection-item avatar">
|
||||
<i class="material-icons circle">
|
||||
{% if d.device_type == 'email' %}mail
|
||||
{% elif d.device_type == 'app' %}phone_android
|
||||
{% else %}vpn_key{% endif %}
|
||||
</i>
|
||||
<span class="title"><strong>{{ d.name }} - {{ d.get_device_type_display }}</strong></span>
|
||||
<p>
|
||||
{% if not d.setup_complete %}
|
||||
<a href="{% url 'django_2fa:device-complete' d.id %}">Complete Setup</a><br>
|
||||
{% endif %}
|
||||
Added: {{ d.created|date:"D, dS M Y" }}
|
||||
</p>
|
||||
<a href="{% url 'django_2fa:device-remove' d.id %}" title="remove" class="secondary-content"
|
||||
onclick="return confirm('Are sure you wish to remove this device?')">
|
||||
<i class="material-icons">delete</i>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
76
markdownblog/markdownblog/templates/2fa/verify.html
Normal file
76
markdownblog/markdownblog/templates/2fa/verify.html
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{% extends "base/base.html" %}
|
||||
{% load i18n static %}
|
||||
{% block title %}{% translate "Verify authenticator app" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col s12">
|
||||
{% if complete_setup %}
|
||||
<h3>{% translate 'Verify your authorization device.' %}</h3>
|
||||
{% else %}
|
||||
<h3>{% translate 'Please authenticate with your 2FA token' %}</h3>
|
||||
{% endif %}
|
||||
<hr>
|
||||
{% if form.errors and not form.non_field_errors %}
|
||||
<p class="errornote">
|
||||
{% if form.errors.items|length == 1 %}{% translate "Please correct the error below." %}{% else %}
|
||||
{% translate "Please correct the errors below." %}{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<form action="{{ request.path }}" method="post" id="mfa-form" class="col s12">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="{{ next_field }}" value="{{ next }}">
|
||||
{% if form.non_field_errors %}
|
||||
<div class="form-row">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<b><p>{% translate '2FA Factor:' %} {{ device.name }}</p></b>
|
||||
<p>
|
||||
{% if device.device_type == 'email' %}
|
||||
{% translate 'Check your e-mail for your authorization code.' %}
|
||||
{% elif device.device_type == 'app' %}
|
||||
{% if not complete_setup %}
|
||||
{% translate 'Enter code from your authenicator application.' %}{% endif %}
|
||||
{% else %}
|
||||
{% translate 'Use your hardware token to complete sign in.' %}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if complete_setup and device.device_type == 'app' %}
|
||||
<p>
|
||||
{% translate 'Scan QR below in your authenicator app, then enter a code to verify your device.' %}
|
||||
<br>
|
||||
<canvas id="qr"></canvas>
|
||||
<br><br><strong>{% translate 'Provision URL:' %}</strong><br>
|
||||
<pre>{{ device.provision_url }}</pre>
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="input-field col s12 l6">
|
||||
{{ form.mfa_code.errors }}
|
||||
{{ form.mfa_code }}
|
||||
{{ form.mfa_code.label_tag }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12 l6">
|
||||
<button class="btn waves-effect waves-light" type="submit">{% translate 'Continue' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% if complete_setup and device.device_type == 'app' %}
|
||||
<script src="{% static '2fa/qrious.min.js' %}"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var qr = new QRious({
|
||||
element: document.getElementById('qr'),
|
||||
value: '{{ device.provision_url }}',
|
||||
size: 200
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -61,6 +61,8 @@
|
|||
</li>
|
||||
<li class="no-liststyle"><a class="waves-effect" href="{% url 'admin:index' %}"><i class="material-icons">
|
||||
admin_panel_settings</i>Admin panel</a></li>
|
||||
<li class="no-liststyle"><a class="waves-effect" href="{% url 'django_2fa:devices' %}"><i class="material-icons">
|
||||
vpn_key</i>Manage 2FA</a></li>
|
||||
<li class="no-liststyle"><a class="waves-effect" href="{% url 'logout' %}"><i
|
||||
class="material-icons">logout</i>Logout</a></li>
|
||||
{% if debug %}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
{% block includehere %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
||||
<link rel="stylesheet" href="{% static 'addpost.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'viewblog.css' %}">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
|
@ -13,8 +14,7 @@
|
|||
<form action="{% url 'addpost' %}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<input name="title" type="text" class="posttitle" id="input_title" value="Title">
|
||||
<textarea name="markdown" id="mde">
|
||||
</textarea>
|
||||
<textarea name="markdown" id="mde"></textarea>
|
||||
<div class="row">
|
||||
<div class="col s6">
|
||||
<label>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
import django_2fa.urls
|
||||
|
||||
urlpatterns = [
|
||||
path('', include('blog.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('accounts/', include('django.contrib.auth.urls'))
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
path('accounts/2fa/', include(django_2fa.urls)),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,3 +5,5 @@ markdown2==2.4.3
|
|||
fontawesomefree==6.1.1
|
||||
pygments==2.12.0
|
||||
gunicorn==20.1.0
|
||||
django-2fa==0.9.0
|
||||
django-extensions==3.1.5
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue