Add social auth Github + login page

This commit is contained in:
Loïc Gremaud 2024-10-04 01:01:36 +02:00
parent d7f0d2a7f2
commit 4fba064273
Signed by: Legrems
GPG Key ID: D4620E6DF3E0121D
14 changed files with 199 additions and 45 deletions

View File

@ -20,20 +20,13 @@ import os
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
SECRET_KEY = "django-insecure-changeme"
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-$440wv7cqb$-umfo-x%w_@p3g5kuuk1(!rv#=7*gzndx4_h4ds"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
@ -43,6 +36,7 @@ INSTALLED_APPS = [
"django.contrib.staticfiles",
"django_js_reverse",
"djangobower",
"social_django",
"main",
"users",
"items",
@ -50,13 +44,14 @@ INSTALLED_APPS = [
STATIC_URL = "/static/"
LOGIN_URL = "/social/login/github/"
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static_source"),)
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
"djangobower.finders.BowerFinder",
# "compressor.finders.CompressorFinder",
)
STATIC_ROOT = os.path.join(BASE_DIR, "static")
@ -64,7 +59,6 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static")
STORAGES = {
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
# "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
}
}
@ -121,15 +115,8 @@ TEMPLATES = [
WSGI_APPLICATION = "app.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
@ -146,9 +133,6 @@ AUTH_PASSWORD_VALIDATORS = [
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
@ -160,6 +144,23 @@ USE_TZ = True
SIMPLE_HISTORY_HISTORY_ID_USE_UUID = True
SOCIAL_AUTH_JSONFIELD_ENABLED = True
AUTHENTICATION_BACKENDS = (
# "social_core.backends.open_id.OpenIdAuth",
# "social_core.backends.google.GoogleOpenId",
# "social_core.backends.google.GoogleOAuth2",
# "social_core.backends.google.GoogleOAuth",
# "social_core.backends.twitter.TwitterOAuth",
"social_core.backends.github.GithubOAuth2",
# "social_core.backends.yahoo.YahooOpenId",
# "django.contrib.auth.backends.ModelBackend",
)
SOCIAL_AUTH_GITHUB_KEY = "Ov23li1mXfjodnBPRC7t"
SOCIAL_AUTH_GITHUB_SECRET = "97cf7cc2ae3722511e1483951db48712ab30ff6e"
SOCIAL_AUTH_REDIRECT_IS_HTTPS = True
SOCIAL_AUTH_LOGIN_REDIRECT_URL = "/"
from app.settingsLocal import *

View File

@ -14,8 +14,11 @@ 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.contrib import admin
from django.urls import include, path
from django_js_reverse.views import urls_js
@ -24,5 +27,6 @@ urlpatterns = [
path("items/", include("items.urls")),
path("users/", include("users.urls")),
path("admin/", admin.site.urls),
path('reverse.js', urls_js, name='reverse_js'),
path("social/", include("social_django.urls", namespace="social")),
path("reverse.js", urls_js, name="reverse_js"),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 5.1.1 on 2024-10-03 21:02
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("items", "0006_historicalitem_historicalitemrelation_and_more"),
]
operations = [
migrations.AlterField(
model_name="linkedproperty",
name="property",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="items.property"),
),
migrations.AlterField(
model_name="relationproperty",
name="property",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="items.property"),
),
]

View File

@ -89,7 +89,7 @@ class BaseLinkedProperty(ItemBase):
class Encryption(ItemBase.Encryption):
fields = ItemBase.Encryption.fields + ["value"]
property = models.ForeignKey(Property, on_delete=models.CASCADE)
property = models.ForeignKey(Property, on_delete=models.PROTECT)
# Value is encrypted too
value = models.TextField(max_length=2048)

View File

@ -1,6 +1,6 @@
{% load i18n %}
<div class="card bg-warning mt-4 pt-2 ps-lg-2" v-if="ready">
<div class="card bg-warning mt-4 pt-2 ps-lg-2">
<h5 class="card-header">{% trans "K356 is locked" %}</h5>
<div class="card-body">
<h5 class="card-title">{% trans "K356 needs an unlock..." %}</h5>
@ -8,7 +8,3 @@
<input class="form-control" type="password" v-model="password" @keyup.enter="generate_aes_key(password)" autofocus>
</div>
</div>
<div class="card bg-danger mt-4 pt-2 ps-lg-2 d-flex" v-else>
<h5 class="card-header flex-grow-1 flex-shrink-1 text-center">{% trans "Cannot load the application. Webcrypto must be enabled" %}</h5>
</div>

View File

@ -9,10 +9,6 @@ Loading = {
}
},
mounted: function() {
this.generate_aes_key("asd")
},
methods: {
async generate_aes_key (password) {

View File

@ -1,7 +1,8 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
@login_required
def home(request):
if request.user.is_authenticated:
return render(request, "base.html", {})
return render(request, "login.html", {})

View File

@ -63,6 +63,7 @@ python = "^3.11"
Django = "^5.0"
django-bower = {git = "https://github.com/ArcaniteSolutions/django-bower.git"}
django-simple-history = "^3.7"
social-auth-app-django = "^5.4"
[tool.poetry.dev-dependencies]
black = "^24.4.0"

View File

@ -65,9 +65,7 @@
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">{% trans "More" %}</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
<a class="dropdown-item" href="{% url 'users:logout' %}">{% trans "Logout" %}</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="/admin/">{% trans "Admin" %}</a>
</div>
@ -83,10 +81,17 @@
</nav>
<v-container class="container-xs">
<div class="card bg-danger mt-4 pt-2 ps-lg-2 d-flex" v-if="!ready">
<h5 class="card-header flex-grow-1 flex-shrink-1 text-center">{% trans "Cannot load the application. Webcrypto must be enabled" %}</h5>
</div>
<Loading @update_key="update_key" v-if="locked"></Loading>
<template v-if="!locked">
<router-view></router-view>
</template>
</v-container>
</div>

101
k356/templates/login.html Normal file
View File

@ -0,0 +1,101 @@
{% load i18n static %}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link rel="shortcut icon" href="{% static 'img/favicon.png' %}">
<script src="{% static "vue/index.js" %}"></script>
<script src="{% static "sweetalert2/index" %}"></script>
<script src="{% static "vue-resource/index" %}"></script>
<script src="{% static "js.cookie.min/index.js" %}"></script>
<script src="{% static "vue-router/index.js" %}"></script>
<link href="{% static "bootstrap.min/index.css" %}" rel="stylesheet">
<script src="{% static "bootstrap.bundle.min/index.js" %}"></script>
<link href="{% static "bootswatch.min.css/index.css" %}" rel="stylesheet">
<script src="{% url 'reverse_js' %}" type="text/javascript"></script>
<link href="{% static "vuetify.min/index.css" %}" rel="stylesheet">
<script src="{% static "vuetify/index.js" %}"></script>
<script src="{% static "vuex/index.js" %}"></script>
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css" rel="stylesheet">
<link href="{% static "jetbrains-mono/index" %}">
<style>
.font {
font-family: 'JetBrains Mono', sans-serif;
}
</style>
</head>
<body>
<v-app class="font">
<div id="main" data-app>
<v-content>
<v-container class="container-xs">
<v-row justify="center">
<v-dialog v-model="dialog" persistent max-width="290">
<v-card>
<v-card-title class="text-h5">
{% trans "Login" %}
</v-card-title>
<v-card-text>
{% trans "Select login option" %}
<v-list-item>
<v-list-item-content>
<v-btn tile color="primary" dark class="mb-2" href="{% url 'social:begin' 'github' %}">
{% trans "Github" %}
</v-btn>
</v-list-item-content>
</v-list-item>
</v-card-text>
</v-card>
</v-dialog>
</v-row>
</v-container>
</v-content>
</div>
</v-app>
<script type="text/javascript">
{% include 'scripts.js' %}
</script>
{% for name, path in templates.items %}
<script type="text/x-template" id="{{ name }}">
{% include path %}
</script>
{% endfor %}
<script type="text/javascript">
{% include "vue/login.js" %}
</script>
<script type="text/javascript">
function refresh_csrftoken() {
var csrftoken = Cookies.get('csrftoken');
Vue.http.headers.common['X-CSRFTOKEN'] = csrftoken;
}
refresh_csrftoken();
</script>
</body>
</html>

View File

@ -35,7 +35,7 @@ const approuter = new Vue({
el: "#main",
data: {
uuid: "{{ user_settings.id }}",
ready: null,
ready: false,
},
computed: {
@ -50,8 +50,6 @@ const approuter = new Vue({
Swal.fire({title: "{{_('The application cannot be launched. Webcrypto is not available.<br><br>Try another browser!') | escapejs}}", icon: "error", showConfirmButton: false})
this.ready = false
} else {
// Try to generate a random keyPair and encrypting stuff before accepting the client
@ -65,8 +63,6 @@ const approuter = new Vue({
Swal.fire({title: "{{_('An error occured during testing Webcrypto. Please use a compatible browser.') | escapejs}}", icon: "error", showConfirmButton: false})
this.ready = false
}
}
@ -99,8 +95,8 @@ const approuter = new Vue({
await this.$http.post(
Urls["users:keys"](),
{
privateKey: await this.wrapKey(this.keyPair.privateKey, aes_key, iv_private),
publicKey: await this.wrapKey(this.keyPair.publicKey, aes_key, iv_public),
privateKey: await this.wrapKey(keyPair.privateKey, aes_key, iv_private),
publicKey: await this.wrapKey(keyPair.publicKey, aes_key, iv_public),
}
)
@ -118,6 +114,8 @@ const approuter = new Vue({
Swal.fire({title: "{{_('Error during unwrapping of private key.<br><br>Maybe your password is wrong?') | escapejs}}", icon: "error", showConfirmButton: false})
console.error(err)
}
},

View File

@ -0,0 +1,17 @@
{% include "vue/plugins.js" %}
Vue.config.devtools = true
Vue.use(VueRouter)
Vue.use(Vuex)
Vue.use(EncryptionPlugin)
Vue.config.delimiters = ["[[", "]]"];
const approuter = new Vue({
vuetify: new Vuetify(),
el: "#main",
data: {
dialog: true,
},
})

View File

@ -8,5 +8,6 @@ app_name = "users"
urlpatterns = [
path("keys", views.keys, name="keys"),
path("logout", views.ulogout, name="logout"),
path("k356/validate", views.k356_validate, name="k356.validate"),
]

View File

@ -1,5 +1,7 @@
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.shortcuts import redirect
from django.utils.translation import gettext as _
@ -75,3 +77,10 @@ def keys(request):
"publicKey": us.public_key,
}
)
@login_required
def ulogout(request):
logout(request)
return redirect("main:home")