From 8049bf2194eee1c230c5f3884327829de436c5f8 Mon Sep 17 00:00:00 2001 From: GKJoker98 Date: Mon, 15 Feb 2021 17:32:52 +0100 Subject: [PATCH] directory sort --- .../Contentserver}/__init__.py | 0 .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 145 bytes .../__pycache__/settings.cpython-38.pyc | Bin 0 -> 2819 bytes .../__pycache__/urls.cpython-38.pyc | Bin 0 -> 671 bytes .../__pycache__/wsgi.cpython-38.pyc | Bin 0 -> 570 bytes Contentserver/Contentserver/asgi.py | 16 ++ Contentserver/Contentserver/settings.py | 138 +++++++++ Contentserver/Contentserver/urls.py | 18 ++ Contentserver/Contentserver/wsgi.py | 16 ++ Contentserver/health_view/__init__.py | 0 Contentserver/health_view/admin.py | 22 ++ Contentserver/health_view/apps.py | 5 + Contentserver/health_view/crypto_functions.py | 103 +++++++ Contentserver/health_view/forms.py | 0 Contentserver/health_view/models.py | 54 ++++ Contentserver/health_view/serializers.py | 64 +++++ Contentserver/health_view/tests.py | 3 + Contentserver/health_view/urls.py | 12 + Contentserver/health_view/views.py | 270 ++++++++++++++++++ Licenseserver/Licenseserver/__init__.py | 0 .../{drm_server => Licenseserver}/asgi.py | 0 .../{drm_server => Licenseserver}/settings.py | 0 .../{drm_server => Licenseserver}/urls.py | 0 .../{drm_server => Licenseserver}/wsgi.py | 0 Licenseserver/health_view/admin.py | 19 +- Licenseserver/health_view/cron.py | 5 +- 26 files changed, 725 insertions(+), 20 deletions(-) rename {Licenseserver/drm_server => Contentserver/Contentserver}/__init__.py (100%) create mode 100644 Contentserver/Contentserver/__pycache__/__init__.cpython-38.pyc create mode 100644 Contentserver/Contentserver/__pycache__/settings.cpython-38.pyc create mode 100644 Contentserver/Contentserver/__pycache__/urls.cpython-38.pyc create mode 100644 Contentserver/Contentserver/__pycache__/wsgi.cpython-38.pyc create mode 100644 Contentserver/Contentserver/asgi.py create mode 100644 Contentserver/Contentserver/settings.py create mode 100644 Contentserver/Contentserver/urls.py create mode 100644 Contentserver/Contentserver/wsgi.py create mode 100644 Contentserver/health_view/__init__.py create mode 100644 Contentserver/health_view/admin.py create mode 100644 Contentserver/health_view/apps.py create mode 100644 Contentserver/health_view/crypto_functions.py create mode 100644 Contentserver/health_view/forms.py create mode 100644 Contentserver/health_view/models.py create mode 100644 Contentserver/health_view/serializers.py create mode 100644 Contentserver/health_view/tests.py create mode 100644 Contentserver/health_view/urls.py create mode 100644 Contentserver/health_view/views.py create mode 100644 Licenseserver/Licenseserver/__init__.py rename Licenseserver/{drm_server => Licenseserver}/asgi.py (100%) rename Licenseserver/{drm_server => Licenseserver}/settings.py (100%) rename Licenseserver/{drm_server => Licenseserver}/urls.py (100%) rename Licenseserver/{drm_server => Licenseserver}/wsgi.py (100%) diff --git a/Licenseserver/drm_server/__init__.py b/Contentserver/Contentserver/__init__.py similarity index 100% rename from Licenseserver/drm_server/__init__.py rename to Contentserver/Contentserver/__init__.py diff --git a/Contentserver/Contentserver/__pycache__/__init__.cpython-38.pyc b/Contentserver/Contentserver/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbae16c6c94622819a53edb71f545a1ed5ab0202 GIT binary patch literal 145 zcmWIL<>g`k0?89M;z9Id5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HSenx(7s(yN6 yQl@@+YEp4(QCVt{eo9epJSHTZlX-=vg$h^-$%m4tJ3L;1V literal 0 HcmV?d00001 diff --git a/Contentserver/Contentserver/__pycache__/settings.cpython-38.pyc b/Contentserver/Contentserver/__pycache__/settings.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6029712ff5e5469f69221e1e3c4144f98e9794e GIT binary patch literal 2819 zcmb7GTXWM!6t-l=wX?r9)iE)??wXD_dxqN%}+@$UK`AiIdzx{mu`(LxM z*ze(D@|VWNJ-od)I6zE~fdHZ<*rF~9;XH1|^*9lU^rP@%=4EU*v76A7An7TX(bJHC zB%~k>ncj?^LCP%5!W_&)7CwLlI01`rvX|E9;8ah5)9@jjc^=p2;VgUv=ioe!AHxN> z2%n%#7IOLr@F|J!F1$EFlJMC}5p`zZ5_}Gq;R;;sNmPJq&!wKAFG5~F3D;o><-Rx{ zgXQNU74%aeLjh%ESc%4BG_F#iC+VkQP5%&X=x5Nzvv_}m_c>VC&%;gqV~A_9{D!$I z#A2E9uIcpLoJTmPPS4AAU6w1k4kr%x2zy3YZou4K(&2I@vqc=jOim!Tv!A;Pk>;`q zHg$3yHyIyGUd;_X#LA7K*W{vn1GP61*>)MpQ3p4%O-@}WhkxFuxGlBF7ia~^^f@1R zUlt1Bc075s$AJYM*DesJfPe+=4rs?K9GG1g!Sg=Jb%&Ofv#7^&ZujU|rUSSUp)B{z zw1&j{KYKCKo!ICVrcEp_1X9!F{kp$;>ATzgwPoI0y2cEnlV7)Q-&-$UqEDB)pOPio zWvf@NJzd*3*7m+$zTICnsn6Pews?D0F5bK)htG|5T;B@k>vC~zMc!EPlPhv`1!>Fe zm{#BQxSuYrZba0gKHG7b*C!?r=J}^aK9V~aG)8yiC?5XFY3h*o{qs}APzB@6_XouD z&rC5r;&~XM;|v=aW)C&aO>1zBX(x=Nr)L@QxY1>%P4-;&M4v@-E#5btQL^XXeVZu{ z2(#&EH@O^TRm}xrHIK**rZ}$C!Xq~vYu}fr0n8qCqJ)y0Xj*+}?+}KwG4WN{5%O{U zTv^>zwySNUskUkrO{+BOMyaZ3nyTq%4|&Q~rLMFOd3w63Y^jD;(N+KQgyUtK0$60v zWJE4uJZgtaKRMet8l#P96I$=G z$75Z&gu^2Y$b{&|)CMNz%_O*jYfKs1iM&0bIBnTMmP{(wMwv6Ab@TY~I~MIc*)=;) zu!YFqY=#-s7=*oI(!+~ywJ3SWEYB~Du{f~@7IrCl2SJDf2VG>GTJ1603(^OYp1v5B z!VlcQR?|T%F`oXlX}seyGLW5N&%gd2l8ijXw!{6Uv1|wym22qWcOZw3_t&O`51slB zg#%t*3X=Dg(nGag)}?Z#r3ERa*)*bAve66^Tk|iLCR@C`=k=&;4hHD@D6T;gNY@-% z{IJGh=g6JjQ;Tx4=4X&Np6A6Nq1Lf*)Ih2$HI>a`#rY4W%#V_3V0s?51Te4>Qy3NP zHoj^U9{OX*iAHT|nPCMy8cDd!zw^FGHR@1%Xjh5TsmcTCng~+p2_E)k-Pqra`)_w3X0O zEjX)ew;vcy?7RqGHXbR}3Nq2KV7{uB0GPHu`B4tXn1q4(06T8=$SjT@KzQ4=jz}? zLmuo0sjqAoh8DSl-%l~`Cmf`?IUyBaNJ?=@%!-mE3RBl>X+iu)j3f2W#M~555MN7k qp-xs1#Y5g-DF2uAkF+2qLt5f*oX?9fq)NxeKctfqlA|jj3I77h@37_o literal 0 HcmV?d00001 diff --git a/Contentserver/Contentserver/__pycache__/urls.cpython-38.pyc b/Contentserver/Contentserver/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6883515cb8ef4df743e4b9f81100d9ef8418ffe3 GIT binary patch literal 671 zcmZWmyKdVs6eVd%mMvL!lcm4lp%KuzC^{6)78D86fr~+#*OFYlKvFU4HA|NMLjrW^ zFL4UcslQNU=p~yJDN2F|=aBcoLtf5iQ-b5(JgjaQAwQgWJ|-yM;nLp_B$2cx4dt|9 zoKdG)J!%3Tcs{DbCgPFjK|O9_9#aCr?c|Q|DNJt@8A7y6?=aJ=2-WPb8l%d*Vlsw! zH{UI;88A5k3RC3tNy+IWPk_o)&SdtLU9%$KFXa4!EEhlVrew+NxN0}`Ai)N`Fy)fk zvFZi`N+S)gD%g7>WK*>^95f!-sKAh3^ZB-`C8%B~(~1W4A@X6lC5J@`qBiBq6*w7G ztq&8?SFgli%KUJwK%3Q8Va~o&pZ&Sb{@ujx6JN9!8#r4Y*+lL{TXa5H;U5q+a^U_& z1qe2I)>4JI!?VYfP1hP#tySbUXYXMvhT5Eamp1z2*2W5oN~3R{T%yTOc<&1^JUw+* zpVZMQm=E6bNA!H=JljB51|QFPvEhux>t)03 literal 0 HcmV?d00001 diff --git a/Contentserver/Contentserver/__pycache__/wsgi.cpython-38.pyc b/Contentserver/Contentserver/__pycache__/wsgi.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82432fe187ee64bff2dac6f06f7245233592c9b8 GIT binary patch literal 570 zcmaJYx15cN7~6Bdd%pq_mVf;EU6s!$Paqad0d(h4b;U3Wd%IP%&n+f6^N`~+^C z;K=XcW{Fcz{R=%Yn+PerFp|f59?iVxXP@otqy*#l_ZP*tgpk`7Y(^KsJ}&pmMT6dU<^BZAm9&uzm9<{W2MjSZU2nRcvM*`)Ex7 z6Fj&jIMz73fHGuhItmP~8tcKcFbB476IzRN4NQ0@SZ(EnhF2PvpxIJ5wJI4=gJeY^ znntTq1Z7Q8;JhQ`s;vX24AR!C0<#8(E6-+1!%OA?(s>Atf5*ABrO)I-n9BasRN9(@ z;cv4yd~Pp;jE5)rt7T-Xd#0EANA=I`jq|!ijK5y literal 0 HcmV?d00001 diff --git a/Contentserver/Contentserver/asgi.py b/Contentserver/Contentserver/asgi.py new file mode 100644 index 0000000..0adb35f --- /dev/null +++ b/Contentserver/Contentserver/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for Contentserver 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/3.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Contentserver.settings') + +application = get_asgi_application() diff --git a/Contentserver/Contentserver/settings.py b/Contentserver/Contentserver/settings.py new file mode 100644 index 0000000..bc8ee73 --- /dev/null +++ b/Contentserver/Contentserver/settings.py @@ -0,0 +1,138 @@ +""" +Django settings for Contentserver project. + +Generated by 'django-admin startproject' using Django 3.1.4. + +For more information on this file, see +https://docs.djangoproject.com/en/3.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.1/ref/settings/ +""" + +from pathlib import Path +import os + +# 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/3.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '#^9h3-tg+(r__c)5m9@51#iq+f!e+ifr2&(q3y_3w=-9h2aizr' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['192.168.192.75', '188.195.130.70', '0.0.0.0', 'localhost', '127.0.0.1'] + +CORS_ORIGIN_ALLOW_ALL=True +# Application definition + +INSTALLED_APPS = [ + 'corsheaders', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'health_view' +] + +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 10 +} + + +MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'Contentserver.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], + '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 = 'Contentserver.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/3.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/3.1/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/3.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Europe/Berlin' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.1/howto/static-files/ + +STATIC_URL = '/static/' +LOGIN_REDIRECT_URL = '/' \ No newline at end of file diff --git a/Contentserver/Contentserver/urls.py b/Contentserver/Contentserver/urls.py new file mode 100644 index 0000000..1ada63a --- /dev/null +++ b/Contentserver/Contentserver/urls.py @@ -0,0 +1,18 @@ +from django.urls import include, path +from rest_framework import routers +from health_view import views +from django.contrib import admin + +router = routers.DefaultRouter() +router.register(r'users', views.UserViewSet) +router.register(r'groups', views.GroupViewSet) +router.register(r'folderpartnames', views.GetFolderPartNames) + +# Wire up our API using automatic URL routing. +# Additionally, we include login URLs for the browsable API. +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include(router.urls)), + path('', include('health_view.urls')), + path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) +] \ No newline at end of file diff --git a/Contentserver/Contentserver/wsgi.py b/Contentserver/Contentserver/wsgi.py new file mode 100644 index 0000000..b0bc514 --- /dev/null +++ b/Contentserver/Contentserver/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for Contentserver 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/3.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Contentserver.settings') + +application = get_wsgi_application() diff --git a/Contentserver/health_view/__init__.py b/Contentserver/health_view/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Contentserver/health_view/admin.py b/Contentserver/health_view/admin.py new file mode 100644 index 0000000..dab6fc6 --- /dev/null +++ b/Contentserver/health_view/admin.py @@ -0,0 +1,22 @@ +from django.contrib import admin + +from .models import FolderInfo, FolderPart, JustifiedKey, FolderPart_Name + +admin.site.register(FolderInfo) +admin.site.register(FolderPart) +admin.site.register(FolderPart_Name) +admin.site.register(JustifiedKey) + +#@admin.register(BookInstance) +#class BookInstanceAdmin(admin.ModelAdmin): +# list_display = ('book', 'status', 'borrower', 'due_back', 'id') +# list_filter = ('status', 'due_back')# +# +# fieldsets = ( +# (None, { +# 'fields': ('book','imprint', 'id') +# }), +# ('Availability', { +# 'fields': ('status', 'due_back','borrower') +# }), +# ) \ No newline at end of file diff --git a/Contentserver/health_view/apps.py b/Contentserver/health_view/apps.py new file mode 100644 index 0000000..0d86d70 --- /dev/null +++ b/Contentserver/health_view/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class HealthViewConfig(AppConfig): + name = 'health_view' diff --git a/Contentserver/health_view/crypto_functions.py b/Contentserver/health_view/crypto_functions.py new file mode 100644 index 0000000..e20ffe7 --- /dev/null +++ b/Contentserver/health_view/crypto_functions.py @@ -0,0 +1,103 @@ +import os +import codecs +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_OAEP, AES +from Crypto.Hash import SHA256 +from Crypto.Signature import PKCS1_v1_5 +from Crypto import Random +from base64 import b64decode, b64encode + + +BS = 16 + + +pub_key_contentserver = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYI/jGk6f0LAT2Z6AAQUR7izbi\na5O4Zzaz4WtK00jr3AqbZMVeVZAs+As5RS35PY2BlCuEEza/J5XX1tlbUhGk/Nzu\nyYqlID6ILEk9kUqh1A6EAuNVrcCL174BRLy620pU5m+E61za0tIr1lU+Jhy4ikVK\niGQ+na5a5g0kuzZTHwIDAQAB\n-----END PUBLIC KEY-----' +private_key_contentserver = '-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDYI/jGk6f0LAT2Z6AAQUR7izbia5O4Zzaz4WtK00jr3AqbZMVe\nVZAs+As5RS35PY2BlCuEEza/J5XX1tlbUhGk/NzuyYqlID6ILEk9kUqh1A6EAuNV\nrcCL174BRLy620pU5m+E61za0tIr1lU+Jhy4ikVKiGQ+na5a5g0kuzZTHwIDAQAB\nAoGAFuf9CgKFBrYRkpGZ3d0M5nDzEJzpC1546ChoKAZrUH/B6gUMe7pirLle6yNf\nQ25YDFcJI5arsyd9VGITJ//zGZC1CC9MBL1v4Ey5Vm3OAwcn7aoiPYoZhtNUDGhE\nCKzIrKWlq5wQDfYCjL2zQnCIAq+nZWACI/X+k/bPd37FZpUCQQDdQNQ3Azaq0owx\nd2crResCW4OryvhTPipLNz8AaW2IMuDfxLUKEaTTkU3NOFRRhIddRRA9/vfcHbrw\nlgZ3Vo5NAkEA+hWX0tItz4lL4pSJTc38Tzjb9WyGQPuAINlntnDwOhtvvRYPfTLi\nLb/22btAfgQWSBICxFdO5Ze0A5Dx140VGwJARwVhWYtZh/nv8I0Ae/6EkowntwR/\nM9FXqC9CtPIiq76ROqMc7e999j/FNqPnRQeCoCjkLtJiY7DTahjuWG5bXQJBAIAD\nS5scAV0pz5FlLT+JgGzhEx729WYQF085WjB2cVGdN75Xq4gP4t0+VVKw2ltnJiyw\nI4BznKxD0l689D69Nh8CQQDLkom4Fhkl8CZQLB1cIX9PjNw+KCBkTV92dJmzdmR5\nGE+p7jO849HPS83W21AV6/eyL8VMqDyE6CBzHNr2ITJT\n-----END RSA PRIVATE KEY-----' + +pub_key_licenseserver= "-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCG54kIgf8wi+WLrmg0OLXTsMF7BsYjJ8+mmx1/Ml1Hts2oVoisf8iKbfcC0jWBc1aEibi7EIZK9AWEmgpIHPZpf2Ezt36KX7pjA7CDgZBye/bw+G1CaDGxrN8a18db8c16hNxHMTMiqPm7WAgoyekOzlCT6/rqF+3w2oYuGx1tmQIDAQAB-----END PUBLIC KEY-----" + + +def make_key_pair_rsa(username): + random_generator = Random.new().read + priv_key = RSA.generate(1024, random_generator) + pub_key = priv_key.publickey() + print("new key pair") + print(priv_key.exportKey()) + print(pub_key.exportKey()) + user_smartcard_path = "/tmp/smartcards/" + str(username) + ".txt" + file_object = open(user_smartcard_path, "w+") + file_object.write(priv_key.exportKey().decode('utf-8')) + file_object.write("\n") + file_object.write(pub_key.exportKey().decode('utf-8')) + file_object.close() + return pub_key.exportKey().decode('utf-8') + + +def make_rand_key_aes(): + return os.urandom(32) + + +def pad(s): + return s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode() + + +def unpad(s): + return s[:-ord(s[len(s)-1:])] + + +def encrypt_aes(message, key): + message = message.encode() + raw = pad(message) + cipher = AES.new(key, AES.MODE_ECB) + enc = cipher.encrypt(raw) + return b64encode(enc).decode('utf-8') + + +def decrypt_aes(enc, key): + enc = b64decode(enc) + cipher = AES.new(key, AES.MODE_ECB) + dec = cipher.decrypt(enc) + return dec.decode('utf-8') + + +def make_encrypted_key_content_server(): + random_key = make_rand_key_aes() + key = RSA.importKey(pub_key_contentserver) + pub_key = key.publickey() + encrypted_key = encrypt(random_key, pub_key) + return encrypted_key.hex() + + +def decrypt(ciphertext): + key = RSA.importKey(private_key_contentserver) + cipher = PKCS1_OAEP.new(key) + ciphertext = codecs.decode(ciphertext, 'hex') + return cipher.decrypt(ciphertext) + + +def encrypt(message): + cipher = PKCS1_OAEP.new(pub_key_contentserver) + return cipher.encrypt(message) + + +def sign(message, priv_key): + priv_key = RSA.importKey(priv_key) + signer = PKCS1_v1_5.new(priv_key) + hash_gen = SHA256.new() + hash_gen.update(message.encode()) + return b64encode(signer.sign(hash_gen)).decode('utf-8') + + +def verify(message, signature, pub_key): + pub_key = pub_key.replace("-----BEGIN PUBLIC KEY-----", "") + pub_key = pub_key.replace("-----END PUBLIC KEY-----", "") + pub_key = pub_key.replace(" ", "") + pub_key = ('\n'.join(pub_key[i:i + 64] for i in range(0, len(pub_key), 64))) + pub_key = "-----BEGIN PUBLIC KEY-----\n" + pub_key + "\n-----END PUBLIC KEY-----" + signature = b64decode(signature) + pub_key = RSA.importKey(pub_key) + verifier = PKCS1_v1_5.new(pub_key) + hash_gen = SHA256.new(message.encode()) + return verifier.verify(hash_gen, signature) + + diff --git a/Contentserver/health_view/forms.py b/Contentserver/health_view/forms.py new file mode 100644 index 0000000..e69de29 diff --git a/Contentserver/health_view/models.py b/Contentserver/health_view/models.py new file mode 100644 index 0000000..7cba09a --- /dev/null +++ b/Contentserver/health_view/models.py @@ -0,0 +1,54 @@ +from django.db import models +from django.contrib.auth.models import User +from django.dispatch import receiver +from django.db.models.signals import post_save + + +class FolderInfo(models.Model): + """Adding attributes to default model user""" + patient = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, default="") + pub_key = models.CharField(max_length=300, blank=True, default="") + + def __str__(self): + """String for representing the Model object.""" + return str(self.id) + + +@receiver(post_save, sender=User) +def create_folderinfo(sender, instance, created, **kwargs): + """Creates Folderinfo for user when he is created""" + if created: + FolderInfo.objects.create(patient=instance) + + +class FolderPart_Name(models.Model): + shortcut = models.CharField(max_length=3, default="x") + part_name = models.CharField(max_length=40, primary_key=True, default="x") + + def __str__(self): + """String for representing the Model object.""" + return str(self.part_name) + + +class FolderPart(models.Model): + part_class = models.ForeignKey(FolderPart_Name, on_delete=models.CASCADE, default="") + folder_id = models.ForeignKey(FolderInfo, on_delete=models.CASCADE, default="") + part_context = models.CharField(max_length=500, default="nothing for you") + + class Meta: + unique_together = ('part_class', 'folder_id') + + def __str__(self): + """String for representing the Model object.""" + return self.part_class.part_name + + +class JustifiedKey(models.Model): + part = models.ForeignKey(FolderPart, on_delete=models.CASCADE, null=True, default="") + justified_name = models.ForeignKey(User, on_delete=models.CASCADE, default="") + key = models.CharField(max_length=260, default="") + + + + + diff --git a/Contentserver/health_view/serializers.py b/Contentserver/health_view/serializers.py new file mode 100644 index 0000000..d12f201 --- /dev/null +++ b/Contentserver/health_view/serializers.py @@ -0,0 +1,64 @@ +from abc import ABC + +from django.contrib.auth.models import User, Group +from rest_framework import serializers +from health_view.models import FolderPart, JustifiedKey, FolderPart_Name, FolderInfo + + +class UserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = User + fields = ['url', 'username', 'email', 'groups'] + + +class GroupSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Group + fields = ['url', 'name'] + + +class KeySerializer(serializers.Serializer): + part = serializers.CharField() + justified_name = serializers.CharField(max_length=100) + key = serializers.CharField(max_length=260) + + def create(self, validated_data): + part = FolderPart.objects.get(pk=validated_data.get("part_class")) + justified_name = FolderPart.objects.get(pk=validated_data.get("part_class")) + key = validated_data.get("part_key") + JustifiedKey(part=part, justified_name=justified_name, key=key) + return True + + def update(self, instance, validated_data): + instance.part = FolderPart.objects.get(pk=validated_data.get("part_class")) + instance.justified_name = FolderPart.objects.get(pk=validated_data.get("part_class")) + instance.key = instance.part_context = validated_data.get("part_key") + instance.save() + return True + + +class ContentSerializer(serializers.Serializer): + part_class = serializers.CharField() + folder_id = serializers.CharField() + part_context = serializers.CharField() + + def update(self, instance, validated_data): + instance.part_class = FolderPart_Name.objects.get(pk=validated_data.get("part_class")) + instance.folder_id = FolderInfo.objects.get(pk=validated_data.get("folder_id")) + instance.part_context = validated_data.get("part_context") + instance.save() + return instance + + +class FolderPartSerializer(serializers.Serializer): + part = serializers.CharField() + justified_name = serializers.CharField() + key = serializers.CharField() + + +class FolderPartNameSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = FolderPart_Name() + fields = ['part_name'] + + diff --git a/Contentserver/health_view/tests.py b/Contentserver/health_view/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/Contentserver/health_view/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/Contentserver/health_view/urls.py b/Contentserver/health_view/urls.py new file mode 100644 index 0000000..a7c6760 --- /dev/null +++ b/Contentserver/health_view/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('key//', views.get_key), + path('content//', views.get_content), + path('folder/create/', views.create_new_folder), + path('create/key/', views.create_key), + path('folder/read/', views.read_folder), + path('folder/write/', views.write_folder), + path('manage/delete/', views.delete_justified_key), +] \ No newline at end of file diff --git a/Contentserver/health_view/views.py b/Contentserver/health_view/views.py new file mode 100644 index 0000000..6a719cb --- /dev/null +++ b/Contentserver/health_view/views.py @@ -0,0 +1,270 @@ +from rest_framework import viewsets, permissions +from django.http import HttpResponse, JsonResponse +from django.views.decorators.csrf import csrf_exempt +from rest_framework.parsers import JSONParser +from health_view.serializers import * +from health_view.crypto_functions import * +from datetime import datetime +from rest_framework.decorators import api_view, permission_classes +from rest_framework.permissions import IsAdminUser +from rest_framework.response import Response +import json + + +@csrf_exempt +def get_key(request, name, part_name="", justified=""): + user_obj = User.objects.get(username=name) + justified_obj = User.objects.get(username=justified) + folderinfo = user_obj.folderinfo + folderpart_obj = FolderPart.objects.get(part_class=part_name, folder_id=folderinfo) + key = JustifiedKey.objects.filter(justified_name=justified_obj, part=folderpart_obj).first() + if request.method == 'GET': + serializer = KeySerializer(key) + return JsonResponse(serializer.data) + elif request.method == 'POST': + data = JSONParser().parse(request) + serializer = KeySerializer(key, data=data) + if serializer.is_valid(): + serializer.save() + return JsonResponse(serializer.data, status=201) + return JsonResponse(serializer.errors, status=400) + + +@csrf_exempt +def get_content(request, name, part_name=""): + user_obj = User.objects.get(username=name) + folderinfo = user_obj.folderinfo + folderpart_obj = FolderPart.objects.get(part_class=part_name, folder_id=folderinfo) + if request.method == 'GET': + serializer = ContentSerializer(folderpart_obj) + return JsonResponse(serializer.data) + elif request.method == 'POST': + data = json.loads(request.body) + serializer = ContentSerializer(folderpart_obj, data=data) + if serializer.is_valid(): + serializer.save() + return JsonResponse(serializer.data, status=201) + return JsonResponse(serializer.errors, status=400) + + +def create_signature_string(license): + signature_string = license["patient"] + "&" + license["justified"] + "&" + license["creator"] + "&" + license["expdate"].replace(" ", ",") + "&" + license["permissions"] + "&" + license["folderparts"] + signature_string = signature_string.replace(" ", "") + return signature_string + + +def create_signature_string_certificate(license): + signature_string = license["patient"] + "&" + license["justified"] + "&" + license["creator"] + "&" + license["expdate"].replace(" ", ",") + "&" + license["permissions"] + "&" + license["folderparts"] + "&" + license["signature"] + "&" + license['content_key'] + signature_string = signature_string.replace(" ", "") + return signature_string + + +def get_creator(license): + creator = User.objects.get(username=license["creator"]) + return creator + + +def get_pubkey(user): + pubkey = user.folderinfo.pub_key + return pubkey + + +def check_expiration_date(license): + exp_date = license["expdate"] + print(exp_date) + for fmt in ('%d-%m-%Y %H:%M', '%d/%m/%Y %H:%M', '%d/%m/%Y', '%d-%m-%Y'): + try: + datetime_object = datetime.strptime(exp_date, fmt) + break + except ValueError: + pass + try: + return datetime.now() < datetime_object + except Exception: + return False + + +def check_permissions(license, part, permission): + if part == "": + return True + if permission not in license["permissions"]: + return False + if part not in license["folderparts"]: + return False + return True + + +def check_change_siganture(pubkey, user_sign, datetime_given, content): + message = datetime_given + "|" + content + if verify(message, user_sign, pubkey): + return True + return False + + +def check_license(license, folderpart="", permission=""): + creator = get_creator(license) + if not verify(create_signature_string(license), license['signature'], get_pubkey(creator)): + return False + if not verify(create_signature_string_certificate(license), license['serversign'], pub_key_licenseserver): + return False + if not check_expiration_date(license): + return False + if not check_permissions(license, folderpart, permission): + return False + return True + + +@csrf_exempt +def read_folder(request): + if request.method == 'POST': + data = json.loads(request.body) + license = data[0] + folderpart = data[1] + if not check_license(license, folderpart, "Read"): + return HttpResponse(status=404) + content_key = license['content_key'] + content_key_decrypted = decrypt(content_key) + patient = User.objects.get(username=license["patient"]) + part_class = FolderPart_Name.objects.get(part_name=folderpart) + part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class) + justified = User.objects.get(username=license["justified"]) + pubkey_justified = justified.folderinfo.pub_key + if len(data) == 3: + justified = User.objects.get(username=license["creator"]) + key_obj = JustifiedKey.objects.get(part=part, justified_name=justified) + content = part.part_context + decrypt_content = decrypt_aes(content, content_key_decrypted) + response_obj = {'content': decrypt_content, + 'key': key_obj.key, + 'pubkey': pubkey_justified} + return JsonResponse(response_obj, status=201) + + +@csrf_exempt +def write_folder(request): + if request.method == 'POST': + data = json.loads(request.body) + license = data[0] + folderpart = data[1] + content = data[2] + datetime_given = data[3] + user_sign = data[4] + if not check_license(license, folderpart, "Write"): + return HttpResponse(status=404) + content_key = license['content_key'] + datetime_given_formatted = datetime.strptime(datetime_given, '%Y-%m-%d|%H:%M:%S') + date_difference = datetime.now() - datetime_given_formatted + content_key_decrypt = decrypt(content_key) + patient = User.objects.get(username=license["patient"]) + part_class = FolderPart_Name.objects.get(part_name=folderpart) + part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class) + justified = User.objects.get(username=license["justified"]) + if date_difference.seconds//60.0 > 4.0 or not check_change_siganture(get_pubkey(justified), user_sign, datetime_given, content): + return HttpResponse(status=404) + content = folderpart + content + part.part_context = encrypt_aes(content, content_key_decrypt) + if JustifiedKey.objects.filter(part=part, justified_name=justified).exists(): + part.save() + json_obj = {'works': 'fined'} + return JsonResponse(json_obj, status=201) + + +@csrf_exempt +def create_new_folder(request): + if request.method == 'POST': + data = json.loads(request.body) + print(data) + license = data[0] + if not check_license(license): + return HttpResponse(status=404) + content_key = license['content_key'] + content_key_decrypt = decrypt(content_key) + patient = User.objects.get(username=license["patient"]) + for c in range(1, len(data)): + part_class = data[c]["part_class"] + content = data[c]["content"] + content = part_class + content + encrypted_key = data[c]["encrypted_key"] + encrypted_content = encrypt_aes(content, content_key_decrypt) + part_class = FolderPart_Name.objects.get(part_name=part_class) + part = FolderPart(folder_id=patient.folderinfo, part_class=part_class, part_context=encrypted_content) + part.save() + justified = User.objects.get(username=license["justified"]) + justified_key = JustifiedKey(part=part, justified_name=justified, key=encrypted_key) + justified_key.save() + json_obj = {'works': 'fined'} + return JsonResponse(json_obj, status=201) + + +@csrf_exempt +def create_key(request): + if request.method == 'POST': + data = json.loads(request.body) + license = data[0] + part_class = data[1] + key = data[2] + if not check_license(license): + return HttpResponse(status=404) + patient = User.objects.get(username=license["patient"]) + part_class = FolderPart_Name.objects.get(part_name=part_class) + justified = User.objects.get(username=license["justified"]) + part = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=part_class) + if not JustifiedKey.objects.filter(part=part, justified_name=justified, key=key).exists(): + justified_key = JustifiedKey(part=part, justified_name=justified, key=key) + justified_key.save() + content_response = {"done": 1} + return JsonResponse(content_response, status=201) + + +@api_view(['POST']) +@csrf_exempt +@permission_classes([IsAdminUser]) +def delete_justified_key(request): + post_content = json.loads(request.body) + print(post_content) + patient = post_content['patient'] + justified = post_content['justified'] + folder_parts_delete_key = post_content['folder_parts'] + old_total_key = post_content['old_total_key'] + new_total_key = post_content['new_total_key'] + old_total_key_decrypt = decrypt(old_total_key) + new_total_key_decrypt = decrypt(new_total_key) + patient = User.objects.get(username=patient) + justified = User.objects.get(username=justified) + all_folder_parts = FolderPart_Name.objects.all().values_list() + for part in all_folder_parts: + folder_part_name_object = FolderPart_Name.objects.get(part_name=part[1]) + folder_part_object = FolderPart.objects.get(part_class=folder_part_name_object,folder_id=patient.folderinfo) + decrypted_content = decrypt_aes(folder_part_object.part_context, old_total_key_decrypt) + encrypted_content = encrypt_aes(decrypted_content, new_total_key_decrypt) + folder_part_object.part_context = encrypted_content + folder_part_object.save() + for part in folder_parts_delete_key: + folder_part_name_object = FolderPart_Name.objects.get(part_name=part) + folder_part_object = FolderPart.objects.get(folder_id=patient.folderinfo, part_class=folder_part_name_object) + key = JustifiedKey.objects.filter(part=folder_part_object, justified_name=justified) + key.delete() + return Response(status=201) + + +class UserViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = User.objects.all().order_by('-date_joined') + serializer_class = UserSerializer + permission_classes = [permissions.IsAuthenticated] + + +class GroupViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows groups to be viewed or edited. + """ + queryset = Group.objects.all() + serializer_class = GroupSerializer + permission_classes = [permissions.IsAuthenticated] + + +class GetFolderPartNames(viewsets.ModelViewSet): + queryset = FolderPart_Name.objects.all() + serializer_class = FolderPartNameSerializer diff --git a/Licenseserver/Licenseserver/__init__.py b/Licenseserver/Licenseserver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Licenseserver/drm_server/asgi.py b/Licenseserver/Licenseserver/asgi.py similarity index 100% rename from Licenseserver/drm_server/asgi.py rename to Licenseserver/Licenseserver/asgi.py diff --git a/Licenseserver/drm_server/settings.py b/Licenseserver/Licenseserver/settings.py similarity index 100% rename from Licenseserver/drm_server/settings.py rename to Licenseserver/Licenseserver/settings.py diff --git a/Licenseserver/drm_server/urls.py b/Licenseserver/Licenseserver/urls.py similarity index 100% rename from Licenseserver/drm_server/urls.py rename to Licenseserver/Licenseserver/urls.py diff --git a/Licenseserver/drm_server/wsgi.py b/Licenseserver/Licenseserver/wsgi.py similarity index 100% rename from Licenseserver/drm_server/wsgi.py rename to Licenseserver/Licenseserver/wsgi.py diff --git a/Licenseserver/health_view/admin.py b/Licenseserver/health_view/admin.py index 9e1977d..92e7df6 100644 --- a/Licenseserver/health_view/admin.py +++ b/Licenseserver/health_view/admin.py @@ -1,26 +1,9 @@ from django.contrib import admin -from .models import Author, Genre, Book, BookInstance, FolderInfo, Permission, License, FolderPart +from .models import FolderInfo, Permission, License, FolderPart -#admin.site.register(Book) -#admin.site.register(Author) -#admin.site.register(Genre) admin.site.register(FolderInfo) admin.site.register(License) admin.site.register(FolderPart) admin.site.register(Permission) - -#@admin.register(BookInstance) -#class BookInstanceAdmin(admin.ModelAdmin): -# list_display = ('book', 'status', 'borrower', 'due_back', 'id') -# list_filter = ('status', 'due_back')# -# -# fieldsets = ( -# (None, { -# 'fields': ('book','imprint', 'id') -# }), -# ('Availability', { -# 'fields': ('status', 'due_back','borrower') -# }), -# ) \ No newline at end of file diff --git a/Licenseserver/health_view/cron.py b/Licenseserver/health_view/cron.py index 5a5d460..5674f49 100644 --- a/Licenseserver/health_view/cron.py +++ b/Licenseserver/health_view/cron.py @@ -6,8 +6,9 @@ import requests import json -loginname_restapi = 'gabi' -passwort_restapi = 'Lolo7138' +#needs logindata from admin account form Contentserver +loginname_restapi = '' +passwort_restapi = '' def check_exp_date():