diff --git a/k356/app/settings.py b/k356/app/settings.py index 7113879..162b32b 100644 --- a/k356/app/settings.py +++ b/k356/app/settings.py @@ -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 * diff --git a/k356/app/urls.py b/k356/app/urls.py index ed606a3..53b12c2 100644 --- a/k356/app/urls.py +++ b/k356/app/urls.py @@ -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"), ] diff --git a/k356/items/migrations/0007_alter_linkedproperty_property_and_more.py b/k356/items/migrations/0007_alter_linkedproperty_property_and_more.py new file mode 100644 index 0000000..be26a84 --- /dev/null +++ b/k356/items/migrations/0007_alter_linkedproperty_property_and_more.py @@ -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"), + ), + ] diff --git a/k356/items/models.py b/k356/items/models.py index fb0804b..2fb45ca 100644 --- a/k356/items/models.py +++ b/k356/items/models.py @@ -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) diff --git a/k356/main/templates/components/Loading/template.html b/k356/main/templates/components/Loading/template.html index 0e9aa4c..fcd0561 100644 --- a/k356/main/templates/components/Loading/template.html +++ b/k356/main/templates/components/Loading/template.html @@ -1,6 +1,6 @@ {% load i18n %} -
+
{% trans "K356 is locked" %}
{% trans "K356 needs an unlock..." %}
@@ -8,7 +8,3 @@
- -
-
{% trans "Cannot load the application. Webcrypto must be enabled" %}
-
diff --git a/k356/main/templates/components/Loading/vue.js b/k356/main/templates/components/Loading/vue.js index 5a5d2fa..59a9d70 100644 --- a/k356/main/templates/components/Loading/vue.js +++ b/k356/main/templates/components/Loading/vue.js @@ -9,10 +9,6 @@ Loading = { } }, - mounted: function() { - this.generate_aes_key("asd") - }, - methods: { async generate_aes_key (password) { diff --git a/k356/main/views.py b/k356/main/views.py index 62812a7..e2eba68 100644 --- a/k356/main/views.py +++ b/k356/main/views.py @@ -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", {}) diff --git a/k356/pyproject.toml b/k356/pyproject.toml index 017fa8b..52a0f31 100644 --- a/k356/pyproject.toml +++ b/k356/pyproject.toml @@ -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" diff --git a/k356/templates/base.html b/k356/templates/base.html index af0f006..24163e6 100644 --- a/k356/templates/base.html +++ b/k356/templates/base.html @@ -65,9 +65,7 @@
diff --git a/k356/templates/login.html b/k356/templates/login.html new file mode 100644 index 0000000..4ffb73d --- /dev/null +++ b/k356/templates/login.html @@ -0,0 +1,101 @@ +{% load i18n static %} + + + + + + {% block title %}{% endblock %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + {% trans "Login" %} + + + + + {% trans "Select login option" %} + + + + + {% trans "Github" %} + + + + + + + + + + + + + +
+
+ + + + {% for name, path in templates.items %} + + {% endfor %} + + + + + + + + diff --git a/k356/templates/vue/index.js b/k356/templates/vue/index.js index 942a95b..f19bf0a 100644 --- a/k356/templates/vue/index.js +++ b/k356/templates/vue/index.js @@ -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.

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.

Maybe your password is wrong?') | escapejs}}", icon: "error", showConfirmButton: false}) + console.error(err) + } }, diff --git a/k356/templates/vue/login.js b/k356/templates/vue/login.js new file mode 100644 index 0000000..fd19b33 --- /dev/null +++ b/k356/templates/vue/login.js @@ -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, + }, +}) diff --git a/k356/users/urls.py b/k356/users/urls.py index 8ff3d08..e32a505 100644 --- a/k356/users/urls.py +++ b/k356/users/urls.py @@ -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"), ] diff --git a/k356/users/views.py b/k356/users/views.py index 58d5927..8444033 100644 --- a/k356/users/views.py +++ b/k356/users/views.py @@ -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")