Add social auth Github + login page
This commit is contained in:
parent
d7f0d2a7f2
commit
4fba064273
@ -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 *
|
||||
|
||||
|
||||
@ -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"),
|
||||
]
|
||||
|
||||
@ -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"),
|
||||
),
|
||||
]
|
||||
@ -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)
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -9,10 +9,6 @@ Loading = {
|
||||
}
|
||||
},
|
||||
|
||||
mounted: function() {
|
||||
this.generate_aes_key("asd")
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
async generate_aes_key (password) {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
@login_required
|
||||
def home(request):
|
||||
return render(request, "base.html", {})
|
||||
if request.user.is_authenticated:
|
||||
return render(request, "base.html", {})
|
||||
|
||||
return render(request, "login.html", {})
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
101
k356/templates/login.html
Normal 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>
|
||||
|
||||
@ -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)
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
17
k356/templates/vue/login.js
Normal file
17
k356/templates/vue/login.js
Normal 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,
|
||||
},
|
||||
})
|
||||
@ -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"),
|
||||
]
|
||||
|
||||
@ -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")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user