From 9636a0214eed129cb1c3d7c48b548d1aa9015141 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Tue, 14 Sep 2021 07:43:25 -0700 Subject: [PATCH 1/9] Update Installation_on_CentOS_7.md --- docs/Installation_on_CentOS_7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Installation_on_CentOS_7.md b/docs/Installation_on_CentOS_7.md index 1532188..aa050bc 100644 --- a/docs/Installation_on_CentOS_7.md +++ b/docs/Installation_on_CentOS_7.md @@ -1,6 +1,6 @@ # Installation on CentOS 7 -This document has not been updated for Crypt Server 3. Pull requests to update this are gratefully accepted. +This document has not been updated for several years and should only be used for version 2 of Crypt server. Pull requests to update this are gratefully accepted. All commands should be run as root, unless specified. From e11e9514f32c97daed10a8d4114757b813f3c2a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Feb 2022 08:02:51 +0000 Subject: [PATCH 2/9] Bump django from 2.2.24 to 2.2.27 in /setup Bumps [django](https://github.com/django/django) from 2.2.24 to 2.2.27. - [Release notes](https://github.com/django/django/releases) - [Commits](https://github.com/django/django/compare/2.2.24...2.2.27) --- updated-dependencies: - dependency-name: django dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- setup/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/requirements.txt b/setup/requirements.txt index a6c5dd3..49be29d 100644 --- a/setup/requirements.txt +++ b/setup/requirements.txt @@ -6,7 +6,7 @@ black==21.7b0 cffi==1.12 Click==8.0.1 cryptography==3.3.2 -Django==2.2.24 +Django==2.2.27 django-bootstrap3==11.0.0 django-bootstrap4==0.0.7 django-debug-toolbar==1.11.1 From d345ab692c1e302eddd6a4c1e673ce7ac1861a46 Mon Sep 17 00:00:00 2001 From: fortiko Date: Sat, 5 Mar 2022 14:49:15 +0100 Subject: [PATCH 3/9] Add missing tz import for timezone support to work Without this import, pytz.timezone will fail every time. --- server/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/views.py b/server/views.py index abe95bb..051bd82 100644 --- a/server/views.py +++ b/server/views.py @@ -3,6 +3,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.template import RequestContext, Template, Context import json +import tz import copy from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.http import HttpResponse, Http404, JsonResponse From 8027ba67073efe4954c070ec6234f8aba14374b0 Mon Sep 17 00:00:00 2001 From: fortiko Date: Sat, 5 Mar 2022 15:48:45 +0100 Subject: [PATCH 4/9] Update views.py --- server/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/views.py b/server/views.py index 051bd82..62be8ed 100644 --- a/server/views.py +++ b/server/views.py @@ -3,7 +3,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.template import RequestContext, Template, Context import json -import tz +import pytz import copy from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.http import HttpResponse, Http404, JsonResponse From afe96316bbef389a1ea18a3b89ab5f54364dca01 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 28 Mar 2022 06:14:31 -0700 Subject: [PATCH 5/9] Fixes a potential XSS vulnerability in the index view --- server/views.py | 7 ++++--- set_build_no.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/server/views.py b/server/views.py index abe95bb..62c7b2a 100644 --- a/server/views.py +++ b/server/views.py @@ -17,6 +17,7 @@ from django.core.mail import send_mail from django.conf import settings from django.urls import reverse +from django.utils.html import escape # Create your views here. logger = logging.getLogger(__name__) @@ -145,12 +146,12 @@ def tableajax(request): serial_link = '%s' % ( reverse("server:computer_info", args=[machine["id"]]), - machine["serial"], + escape(machine["serial"]), ) computername_link = '%s' % ( reverse("server:computer_info", args=[machine["id"]]), - machine["computername"], + escape(machine["computername"]), ) info_button = 'Info' % ( @@ -160,7 +161,7 @@ def tableajax(request): list_data = [ serial_link, computername_link, - machine["username"], + escape(machine["username"]), formatted_date, info_button, ] diff --git a/set_build_no.py b/set_build_no.py index cf9b827..d22518a 100755 --- a/set_build_no.py +++ b/set_build_no.py @@ -4,7 +4,7 @@ import plistlib import subprocess -current_version = "3.2.0" +current_version = "3.2.1" script_path = os.path.dirname(os.path.realpath(__file__)) From 13611b2e310bda862d7ba1b047ba14981c3f8278 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 28 Mar 2022 06:29:01 -0700 Subject: [PATCH 6/9] UTC please --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 377ad11..da0d9c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ LABEL maintainer="graham@grahamgilbert.com" ENV APP_DIR /home/docker/crypt ENV DEBUG false ENV LANG en -ENV TZ America/New_York +ENV TZ Etc/UTC ENV LC_ALL en_US.UTF-8 COPY setup/requirements.txt /tmp/requirements.txt From 4a9745297a1e09a778ffa2e436b47e52b499b071 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 28 Mar 2022 06:29:41 -0700 Subject: [PATCH 7/9] fix --- set_build_no.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/set_build_no.py b/set_build_no.py index d22518a..da3c045 100755 --- a/set_build_no.py +++ b/set_build_no.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import os import plistlib From d5748bdaad381cffdf24d5f6cb4e65104ab4778d Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 28 Mar 2022 08:19:23 -0700 Subject: [PATCH 8/9] Update base image and squash migrations --- Dockerfile | 2 +- README.md | 30 +-- docker/run.sh | 2 +- docker/run_docker.sh | 2 +- docker/settings_import.py | 2 +- fvserver/context_processors.py | 3 +- fvserver/version.plist | 2 +- remote_build.py | 2 +- .../0001_squashed_0017_merge_20181217_1829.py | 202 ++++++++++++++++++ server/migrations/0006_auto_20150714_0821.py | 16 +- server/migrations/0013_secret_new_secret.py | 20 -- server/migrations/0014_migrate_secrets.py | 31 --- .../0015_secret_remove_old_secret.py | 18 -- server/migrations/0016_auto_20181213_2145.py | 2 +- server/views.py | 6 +- set_build_no.py | 2 +- setup/requirements.txt | 3 +- 17 files changed, 241 insertions(+), 104 deletions(-) create mode 100644 server/migrations/0001_squashed_0017_merge_20181217_1829.py delete mode 100644 server/migrations/0013_secret_new_secret.py delete mode 100644 server/migrations/0014_migrate_secrets.py delete mode 100644 server/migrations/0015_secret_remove_old_secret.py diff --git a/Dockerfile b/Dockerfile index da0d9c1..8e74a57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7.9-alpine3.12 +FROM python:3.10.4-alpine3.15 LABEL maintainer="graham@grahamgilbert.com" diff --git a/README.md b/README.md index 50bef3c..afc2459 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,45 @@ -Crypt-Server -============ -__[Crypt][1]__ is a tool for securely storing secrets such as FileVault 2 recovery keys. It is made up of a client app, and a Django web app for storing the keys. +# Crypt-Server + +**[Crypt][1]** is a tool for securely storing secrets such as FileVault 2 recovery keys. It is made up of a client app, and a Django web app for storing the keys. This Docker image contains the fully configured Crypt Django web app. A default admin user has been preconfigured, use admin/password to login. If you intend on using the server for anything semi-serious it is a good idea to change the password or add a new admin user and delete the default one. -__Features__ -======= +## Features + - Secrets are encrypted in the database - All access is audited - all reasons for retrieval and approval are logged along side the users performing the actions - Two step approval for retrieval of secrets is enabled by default - Approval permission can be given to all users (so just any two users need to approve the retrieval) or a specific group of users - [1]: https://github.com/grahamgilbert/Crypt ## Installation instructions + It is recommended that you use [Docker](https://github.com/grahamgilbert/Crypt-Server/blob/master/docs/Docker.md) to run this, but if you wish to run directly on a host, installation instructions are over in the [docs directory](https://github.com/grahamgilbert/Crypt-Server/blob/master/docs/Installation_on_Ubuntu_1404.md) +### Migrating from versions earlier than Crypt 3.0 + +Crypt 3 changed it's encryption backend, so when migrating from versions earlier than Crypt 3.0, you should first run Crypt 3.2.0 to perform the migration, and then upgrade to the latest version. The last version to support legacy migrations was Crypt 3.2. + ## Settings All settings that would be entered into `settings.py` can also be passed into the Docker container as environment variables. -* ``FIELD_ENCRYPTION_KEY`` - The key to use when encrypting the secrets. This is required. +- `FIELD_ENCRYPTION_KEY` - The key to use when encrypting the secrets. This is required. -* ``SEND_EMAIL`` - Crypt Server can send email notifcations when secrets are requested and approved. Set ``SEND_EMAIL`` to True, and set ``HOST_NAME`` to your server's host and URL scheme (e.g. ``https://crypt.example.com``). For configuring your email settings, see the [Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-EMAIL_HOST). +- `SEND_EMAIL` - Crypt Server can send email notifcations when secrets are requested and approved. Set `SEND_EMAIL` to True, and set `HOST_NAME` to your server's host and URL scheme (e.g. `https://crypt.example.com`). For configuring your email settings, see the [Django documentation](https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-EMAIL_HOST). -* ``EMAIL_SENDER`` - The email address to send emaiil notifications from when secrets are requests and approved. Ensure this is verified if you are using SES. Does nothing unless ``SEND_EMAIIL`` is True. +- `EMAIL_SENDER` - The email address to send emaiil notifications from when secrets are requests and approved. Ensure this is verified if you are using SES. Does nothing unless `SEND_EMAIIL` is True. -* ``APPROVE_OWN`` - By default, users with approval permissons can approve their own key requests. By setting this to False in settings.py (or by using the `APPROVE_OWN` environment variable with Docker), users cannot approve their own requests. +- `APPROVE_OWN` - By default, users with approval permissons can approve their own key requests. By setting this to False in settings.py (or by using the `APPROVE_OWN` environment variable with Docker), users cannot approve their own requests. -* ``ALL_APPROVE`` - By default, users need to be explicitly given approval permissions to approve key retrieval requests. By setting this to True in `settings.py`, all users are given this permission when they log in. - -* ``ROTATE_VIEWED_SECRETS`` - With a compatible client (such as Crypt 3.2.0 and greater), Crypt Server can instruct the client to rotate the secret and re-escrow it when the secret has been viewed. Enable by setting this to `True` or by using `ROTATE_VIEWED_SECRETS` and setting to `true`. +- `ALL_APPROVE` - By default, users need to be explicitly given approval permissions to approve key retrieval requests. By setting this to True in `settings.py`, all users are given this permission when they log in. +- `ROTATE_VIEWED_SECRETS` - With a compatible client (such as Crypt 3.2.0 and greater), Crypt Server can instruct the client to rotate the secret and re-escrow it when the secret has been viewed. Enable by setting this to `True` or by using `ROTATE_VIEWED_SECRETS` and setting to `true`. ## Screenshots + Main Page: ![Crypt Main Page](https://raw.github.com/grahamgilbert/Crypt-Server/master/docs/images/home.png) diff --git a/docker/run.sh b/docker/run.sh index 7a8d0b0..ddd7128 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -4,7 +4,7 @@ set -e cd $APP_DIR ADMIN_PASS=${ADMIN_PASS:-} -python3 generate_keyczart.py +# python3 generate_keyczart.py python3 manage.py migrate --noinput if [ ! -z "$ADMIN_PASS" ] ; then diff --git a/docker/run_docker.sh b/docker/run_docker.sh index 7f0882b..7c9dcfa 100755 --- a/docker/run_docker.sh +++ b/docker/run_docker.sh @@ -1,5 +1,6 @@ CWD=`pwd` docker rm -f crypt + docker build -t macadmins/crypt . docker run -d \ -e ADMIN_PASS=pass \ @@ -8,7 +9,6 @@ docker run -d \ --name=crypt \ --restart="always" \ -v "$CWD/crypt.db":/home/docker/crypt/crypt.db \ - -v "$CWD/keyset":/home/docker/crypt/keyset \ -e FIELD_ENCRYPTION_KEY=jKAv1Sde8m6jCYFnmps0iXkUfAilweNVjbvoebBrDwg= \ -p 8000-8050:8000-8050 \ macadmins/crypt diff --git a/docker/settings_import.py b/docker/settings_import.py index 2f3135d..e498e1b 100644 --- a/docker/settings_import.py +++ b/docker/settings_import.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from os import getenv import locale diff --git a/fvserver/context_processors.py b/fvserver/context_processors.py index 7f8ccde..a186d86 100644 --- a/fvserver/context_processors.py +++ b/fvserver/context_processors.py @@ -5,5 +5,6 @@ def crypt_version(request): # return the value you want as a dictionary. you may add multiple values in there. current_dir = os.path.dirname(os.path.realpath(__file__)) - version = plistlib.readPlist(os.path.join(current_dir, "version.plist")) + with open(os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), 'rb') as f: + version = plistlib.load(f) return {"CRYPT_VERSION": version["version"]} diff --git a/fvserver/version.plist b/fvserver/version.plist index 5a1be97..823bbc3 100644 --- a/fvserver/version.plist +++ b/fvserver/version.plist @@ -3,6 +3,6 @@ version - 3.2.0.343 + 3.3.0.354 diff --git a/remote_build.py b/remote_build.py index d626f37..ae10abe 100644 --- a/remote_build.py +++ b/remote_build.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import subprocess import requests diff --git a/server/migrations/0001_squashed_0017_merge_20181217_1829.py b/server/migrations/0001_squashed_0017_merge_20181217_1829.py new file mode 100644 index 0000000..cf4635f --- /dev/null +++ b/server/migrations/0001_squashed_0017_merge_20181217_1829.py @@ -0,0 +1,202 @@ +# Generated by Django 2.2.27 on 2022-03-28 14:50 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +from django.shortcuts import get_object_or_404 + + +# Functions from the following migrations need manual copying. +# Move them and any dependencies into this file, then update the +# RunPython operations to refer to the local versions: +# server.migrations.0003_auto_20150713_1215 +# server.migrations.0007_auto_20150714_0822 +# server.migrations.0010_auto_20180726_1700 + +def move_keys_and_requests(apps, schema_editor): + seen_serials = [("dummy_serial", "dummy_id")] + Computer = apps.get_model("server", "Computer") + Secret = apps.get_model("server", "Secret") + Request = apps.get_model("server", "Request") + for computer in Computer.objects.all(): + # if we've seen the serial before, get the computer that we saw before + target_id = None + for serial, id in seen_serials: + if computer.serial == serial: + target_id = id + break + if target_id == None: + target_id = computer.id + + target_computer = get_object_or_404(Computer, pk=target_id) + # create a new secret + secret = Secret( + computer=target_computer, + secret=computer.recovery_key, + date_escrowed=computer.last_checkin, + ) + secret.save() + + requests = Request.objects.filter(computer=computer) + for request in requests: + request.secret = secret + request.save() + + if target_computer.id != computer.id: + # Dupe computer, bin it + computer.delete() + +class Migration(migrations.Migration): + + replaces = [('server', '0001_initial'), ('server', '0002_auto_20150713_1214'), ('server', '0003_auto_20150713_1215'), ('server', '0004_auto_20150713_1216'), ('server', '0005_auto_20150713_1754'), ('server', '0006_auto_20150714_0821'), ('server', '0007_auto_20150714_0822'), ('server', '0008_auto_20150814_2140'), ('server', '0009_secret_rotation_required'), ('server', '0010_auto_20180726_1700'), ('server', '0011_manual_unique_serials'), ('server', '0012_auto_20181128_2038'), ('server', '0016_auto_20181213_2145'), ('server', '0009_auto_20180430_2024'), ('server', '0017_merge_20181217_1829')] + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + + operations = [ + migrations.CreateModel( + name='Computer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('recovery_key', models.CharField(max_length=200, verbose_name=b'Recovery Key')), + ('serial', models.CharField(max_length=200, verbose_name=b'Serial Number')), + ('username', models.CharField(max_length=200, verbose_name=b'User Name')), + ('computername', models.CharField(max_length=200, verbose_name=b'Computer Name')), + ('last_checkin', models.DateTimeField(blank=True, null=True)), + ], + options={ + 'ordering': ['serial'], + 'permissions': (('can_approve', 'Can approve requests to see encryption keys'),), + }, + ), + migrations.CreateModel( + name='Secret', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('secret', models.CharField(max_length=256)), + ('secret_type', models.CharField(choices=[(b'recovery_key', b'Recovery Key'), (b'password', b'Password')], default=b'recovery_key', max_length=256)), + ('date_escrowed', models.DateTimeField(auto_now_add=True)), + ('computer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='server.Computer')), + ], + ), + migrations.CreateModel( + name='Request', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('approved', models.NullBooleanField(verbose_name=b'Approved?')), + ('reason_for_request', models.TextField()), + ('reason_for_approval', models.TextField(blank=True, null=True, verbose_name=b'Approval Notes')), + ('date_requested', models.DateTimeField(auto_now_add=True)), + ('date_approved', models.DateTimeField(blank=True, null=True)), + ('current', models.BooleanField(default=True)), + ('auth_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='auth_user', to=settings.AUTH_USER_MODEL)), + ('computer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='computers', to='server.Computer')), + ('requesting_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requesting_user', to=settings.AUTH_USER_MODEL)), + ('secret', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='secrets', to='server.Secret')), + ], + ), + migrations.RunPython( + code=move_keys_and_requests, + ), + migrations.RemoveField( + model_name='computer', + name='recovery_key', + ), + migrations.RemoveField( + model_name='request', + name='computer', + ), + migrations.AlterField( + model_name='request', + name='secret', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='server.Secret'), + ), + migrations.AlterModelOptions( + name='secret', + options={'ordering': ['-date_escrowed']}, + ), + migrations.AddField( + model_name='secret', + name='rotation_required', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='computer', + name='serial', + field=models.CharField(max_length=200, unique=True, verbose_name=b'Serial Number'), + ), + migrations.AlterField( + model_name='computer', + name='computername', + field=models.CharField(max_length=200, verbose_name='Computer Name'), + ), + migrations.AlterField( + model_name='computer', + name='serial', + field=models.CharField(max_length=200, unique=True, verbose_name='Serial Number'), + ), + migrations.AlterField( + model_name='computer', + name='username', + field=models.CharField(max_length=200, verbose_name='User Name'), + ), + migrations.AlterField( + model_name='request', + name='approved', + field=models.NullBooleanField(verbose_name='Approved?'), + ), + migrations.AlterField( + model_name='request', + name='reason_for_approval', + field=models.TextField(blank=True, null=True, verbose_name='Approval Notes'), + ), + migrations.AlterField( + model_name='secret', + name='secret_type', + field=models.CharField(choices=[('recovery_key', 'Recovery Key'), ('password', 'Password')], default='recovery_key', max_length=256), + ), + migrations.AlterField( + model_name='request', + name='auth_user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='auth_user', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='request', + name='secret', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='server.Secret'), + ), + migrations.AlterField( + model_name='computer', + name='computername', + field=models.CharField(max_length=200, verbose_name='Computer Name'), + ), + migrations.AlterField( + model_name='computer', + name='serial', + field=models.CharField(max_length=200, verbose_name='Serial Number'), + ), + migrations.AlterField( + model_name='computer', + name='username', + field=models.CharField(max_length=200, verbose_name='User Name'), + ), + migrations.AlterField( + model_name='request', + name='approved', + field=models.NullBooleanField(verbose_name='Approved?'), + ), + migrations.AlterField( + model_name='request', + name='reason_for_approval', + field=models.TextField(blank=True, null=True, verbose_name='Approval Notes'), + ), + migrations.AlterField( + model_name='secret', + name='secret_type', + field=models.CharField(choices=[('recovery_key', 'Recovery Key'), ('password', 'Password')], default='recovery_key', max_length=256), + ), + ] diff --git a/server/migrations/0006_auto_20150714_0821.py b/server/migrations/0006_auto_20150714_0821.py index a1b7e7c..85e0ad8 100644 --- a/server/migrations/0006_auto_20150714_0821.py +++ b/server/migrations/0006_auto_20150714_0821.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.db import models, migrations -import django_extensions.db.fields.encrypted +# import django_extensions.db.fields.encrypted class Migration(migrations.Migration): @@ -10,11 +10,11 @@ class Migration(migrations.Migration): dependencies = [("server", "0005_auto_20150713_1754")] operations = [ - migrations.AlterField( - model_name="secret", - name="secret", - field=django_extensions.db.fields.encrypted.EncryptedCharField( - max_length=256 - ), - ) + # migrations.AlterField( + # model_name="secret", + # name="secret", + # field=django_extensions.db.fields.encrypted.EncryptedCharField( + # max_length=256 + # ), + # ) ] diff --git a/server/migrations/0013_secret_new_secret.py b/server/migrations/0013_secret_new_secret.py deleted file mode 100644 index b3ec5ff..0000000 --- a/server/migrations/0013_secret_new_secret.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2018-11-30 17:59 -from __future__ import unicode_literals - -from django.db import migrations -import encrypted_model_fields.fields - - -class Migration(migrations.Migration): - - dependencies = [("server", "0012_auto_20181128_2038")] - - operations = [ - migrations.AddField( - model_name="secret", - name="new_secret", - field=encrypted_model_fields.fields.EncryptedCharField(default=""), - preserve_default=False, - ) - ] diff --git a/server/migrations/0014_migrate_secrets.py b/server/migrations/0014_migrate_secrets.py deleted file mode 100644 index 2475a7c..0000000 --- a/server/migrations/0014_migrate_secrets.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from server.models import * -from django.db import migrations, models -from django.conf import settings - - -def migrate_secrets(apps, schema_editor): - """ - Migrate the secrets to the new field - """ - - if not hasattr(settings, "FIELD_ENCRYPTION_KEY"): - raise Exception("FIELD_ENCRYPTION_KEY not set in settings.py") - - if settings.FIELD_ENCRYPTION_KEY == "": - raise Exception("FIELD_ENCRYPTION_KEY not configured correctly in settings.py") - - Secret = apps.get_model("server", "Secret") - secrets_to_update = Secret.objects.all() - for secret_to_update in secrets_to_update: - secret_to_update.new_secret = secret_to_update.secret - secret_to_update.save() - - -class Migration(migrations.Migration): - - dependencies = [("server", "0013_secret_new_secret")] - - operations = [migrations.RunPython(migrate_secrets)] diff --git a/server/migrations/0015_secret_remove_old_secret.py b/server/migrations/0015_secret_remove_old_secret.py deleted file mode 100644 index 937d3ab..0000000 --- a/server/migrations/0015_secret_remove_old_secret.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10 on 2018-11-30 17:59 -from __future__ import unicode_literals - -from django.db import migrations -import encrypted_model_fields.fields - - -class Migration(migrations.Migration): - - dependencies = [("server", "0014_migrate_secrets")] - - operations = [ - migrations.RemoveField(model_name="secret", name="secret"), - migrations.RenameField( - model_name="secret", old_name="new_secret", new_name="secret" - ), - ] diff --git a/server/migrations/0016_auto_20181213_2145.py b/server/migrations/0016_auto_20181213_2145.py index 51d1e2d..3a5f9b9 100644 --- a/server/migrations/0016_auto_20181213_2145.py +++ b/server/migrations/0016_auto_20181213_2145.py @@ -7,7 +7,7 @@ class Migration(migrations.Migration): - dependencies = [("server", "0015_secret_remove_old_secret")] + dependencies = [("server", "0012_auto_20181128_2038")] operations = [ migrations.AlterField( diff --git a/server/views.py b/server/views.py index d80a863..e5533f9 100644 --- a/server/views.py +++ b/server/views.py @@ -36,9 +36,9 @@ def cleanup(): def get_server_version(): current_dir = os.path.dirname(os.path.realpath(__file__)) - version = plistlib.readPlist( - os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist") - ) + + with open(os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), 'rb') as f: + version = plistlib.load(f) return version["version"] diff --git a/set_build_no.py b/set_build_no.py index da3c045..6ad8310 100755 --- a/set_build_no.py +++ b/set_build_no.py @@ -4,7 +4,7 @@ import plistlib import subprocess -current_version = "3.2.1" +current_version = "3.3.0" script_path = os.path.dirname(os.path.realpath(__file__)) diff --git a/setup/requirements.txt b/setup/requirements.txt index 49be29d..8f787ac 100644 --- a/setup/requirements.txt +++ b/setup/requirements.txt @@ -3,7 +3,7 @@ asn1crypto==0.24.0 astroid==2.0.4 attrs==18.2.0 black==21.7b0 -cffi==1.12 +cffi==1.15 Click==8.0.1 cryptography==3.3.2 Django==2.2.27 @@ -29,7 +29,6 @@ pycparser==2.19 pycrypto==2.6.1 pyflakes==2.0.0 pylint==2.1.1 -python3-keyczar==0.71rc0 pytz==2018.7 regex==2021.8.3 six==1.9.0 From 34d1d2df4df0ae617fa2c59402ed3d36bb9493ff Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 28 Mar 2022 08:20:52 -0700 Subject: [PATCH 9/9] black --- fvserver/context_processors.py | 4 +- fvserver/version.plist | 2 +- .../0001_squashed_0017_merge_20181217_1829.py | 301 +++++++++++++----- server/migrations/0006_auto_20150714_0821.py | 1 + server/models.py | 2 +- server/views.py | 4 +- 6 files changed, 225 insertions(+), 89 deletions(-) diff --git a/fvserver/context_processors.py b/fvserver/context_processors.py index a186d86..ddfca9c 100644 --- a/fvserver/context_processors.py +++ b/fvserver/context_processors.py @@ -5,6 +5,8 @@ def crypt_version(request): # return the value you want as a dictionary. you may add multiple values in there. current_dir = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), 'rb') as f: + with open( + os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), "rb" + ) as f: version = plistlib.load(f) return {"CRYPT_VERSION": version["version"]} diff --git a/fvserver/version.plist b/fvserver/version.plist index 823bbc3..29d6c63 100644 --- a/fvserver/version.plist +++ b/fvserver/version.plist @@ -3,6 +3,6 @@ version - 3.3.0.354 + 3.3.0.355 diff --git a/server/migrations/0001_squashed_0017_merge_20181217_1829.py b/server/migrations/0001_squashed_0017_merge_20181217_1829.py index cf4635f..cd1addf 100644 --- a/server/migrations/0001_squashed_0017_merge_20181217_1829.py +++ b/server/migrations/0001_squashed_0017_merge_20181217_1829.py @@ -13,6 +13,7 @@ # server.migrations.0007_auto_20150714_0822 # server.migrations.0010_auto_20180726_1700 + def move_keys_and_requests(apps, schema_editor): seen_serials = [("dummy_serial", "dummy_id")] Computer = apps.get_model("server", "Computer") @@ -46,9 +47,26 @@ def move_keys_and_requests(apps, schema_editor): # Dupe computer, bin it computer.delete() + class Migration(migrations.Migration): - replaces = [('server', '0001_initial'), ('server', '0002_auto_20150713_1214'), ('server', '0003_auto_20150713_1215'), ('server', '0004_auto_20150713_1216'), ('server', '0005_auto_20150713_1754'), ('server', '0006_auto_20150714_0821'), ('server', '0007_auto_20150714_0822'), ('server', '0008_auto_20150814_2140'), ('server', '0009_secret_rotation_required'), ('server', '0010_auto_20180726_1700'), ('server', '0011_manual_unique_serials'), ('server', '0012_auto_20181128_2038'), ('server', '0016_auto_20181213_2145'), ('server', '0009_auto_20180430_2024'), ('server', '0017_merge_20181217_1829')] + replaces = [ + ("server", "0001_initial"), + ("server", "0002_auto_20150713_1214"), + ("server", "0003_auto_20150713_1215"), + ("server", "0004_auto_20150713_1216"), + ("server", "0005_auto_20150713_1754"), + ("server", "0006_auto_20150714_0821"), + ("server", "0007_auto_20150714_0822"), + ("server", "0008_auto_20150814_2140"), + ("server", "0009_secret_rotation_required"), + ("server", "0010_auto_20180726_1700"), + ("server", "0011_manual_unique_serials"), + ("server", "0012_auto_20181128_2038"), + ("server", "0016_auto_20181213_2145"), + ("server", "0009_auto_20180430_2024"), + ("server", "0017_merge_20181217_1829"), + ] initial = True @@ -56,147 +74,260 @@ class Migration(migrations.Migration): migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] - operations = [ migrations.CreateModel( - name='Computer', + name="Computer", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('recovery_key', models.CharField(max_length=200, verbose_name=b'Recovery Key')), - ('serial', models.CharField(max_length=200, verbose_name=b'Serial Number')), - ('username', models.CharField(max_length=200, verbose_name=b'User Name')), - ('computername', models.CharField(max_length=200, verbose_name=b'Computer Name')), - ('last_checkin', models.DateTimeField(blank=True, null=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "recovery_key", + models.CharField(max_length=200, verbose_name=b"Recovery Key"), + ), + ( + "serial", + models.CharField(max_length=200, verbose_name=b"Serial Number"), + ), + ( + "username", + models.CharField(max_length=200, verbose_name=b"User Name"), + ), + ( + "computername", + models.CharField(max_length=200, verbose_name=b"Computer Name"), + ), + ("last_checkin", models.DateTimeField(blank=True, null=True)), ], options={ - 'ordering': ['serial'], - 'permissions': (('can_approve', 'Can approve requests to see encryption keys'),), + "ordering": ["serial"], + "permissions": ( + ("can_approve", "Can approve requests to see encryption keys"), + ), }, ), migrations.CreateModel( - name='Secret', + name="Secret", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('secret', models.CharField(max_length=256)), - ('secret_type', models.CharField(choices=[(b'recovery_key', b'Recovery Key'), (b'password', b'Password')], default=b'recovery_key', max_length=256)), - ('date_escrowed', models.DateTimeField(auto_now_add=True)), - ('computer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='server.Computer')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("secret", models.CharField(max_length=256)), + ( + "secret_type", + models.CharField( + choices=[ + (b"recovery_key", b"Recovery Key"), + (b"password", b"Password"), + ], + default=b"recovery_key", + max_length=256, + ), + ), + ("date_escrowed", models.DateTimeField(auto_now_add=True)), + ( + "computer", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="server.Computer", + ), + ), ], ), migrations.CreateModel( - name='Request', + name="Request", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('approved', models.NullBooleanField(verbose_name=b'Approved?')), - ('reason_for_request', models.TextField()), - ('reason_for_approval', models.TextField(blank=True, null=True, verbose_name=b'Approval Notes')), - ('date_requested', models.DateTimeField(auto_now_add=True)), - ('date_approved', models.DateTimeField(blank=True, null=True)), - ('current', models.BooleanField(default=True)), - ('auth_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='auth_user', to=settings.AUTH_USER_MODEL)), - ('computer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='computers', to='server.Computer')), - ('requesting_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='requesting_user', to=settings.AUTH_USER_MODEL)), - ('secret', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='secrets', to='server.Secret')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("approved", models.NullBooleanField(verbose_name=b"Approved?")), + ("reason_for_request", models.TextField()), + ( + "reason_for_approval", + models.TextField( + blank=True, null=True, verbose_name=b"Approval Notes" + ), + ), + ("date_requested", models.DateTimeField(auto_now_add=True)), + ("date_approved", models.DateTimeField(blank=True, null=True)), + ("current", models.BooleanField(default=True)), + ( + "auth_user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="auth_user", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "computer", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="computers", + to="server.Computer", + ), + ), + ( + "requesting_user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="requesting_user", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "secret", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="secrets", + to="server.Secret", + ), + ), ], ), migrations.RunPython( code=move_keys_and_requests, ), migrations.RemoveField( - model_name='computer', - name='recovery_key', + model_name="computer", + name="recovery_key", ), migrations.RemoveField( - model_name='request', - name='computer', + model_name="request", + name="computer", ), migrations.AlterField( - model_name='request', - name='secret', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='server.Secret'), + model_name="request", + name="secret", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="server.Secret" + ), ), migrations.AlterModelOptions( - name='secret', - options={'ordering': ['-date_escrowed']}, + name="secret", + options={"ordering": ["-date_escrowed"]}, ), migrations.AddField( - model_name='secret', - name='rotation_required', + model_name="secret", + name="rotation_required", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='computer', - name='serial', - field=models.CharField(max_length=200, unique=True, verbose_name=b'Serial Number'), + model_name="computer", + name="serial", + field=models.CharField( + max_length=200, unique=True, verbose_name=b"Serial Number" + ), ), migrations.AlterField( - model_name='computer', - name='computername', - field=models.CharField(max_length=200, verbose_name='Computer Name'), + model_name="computer", + name="computername", + field=models.CharField(max_length=200, verbose_name="Computer Name"), ), migrations.AlterField( - model_name='computer', - name='serial', - field=models.CharField(max_length=200, unique=True, verbose_name='Serial Number'), + model_name="computer", + name="serial", + field=models.CharField( + max_length=200, unique=True, verbose_name="Serial Number" + ), ), migrations.AlterField( - model_name='computer', - name='username', - field=models.CharField(max_length=200, verbose_name='User Name'), + model_name="computer", + name="username", + field=models.CharField(max_length=200, verbose_name="User Name"), ), migrations.AlterField( - model_name='request', - name='approved', - field=models.NullBooleanField(verbose_name='Approved?'), + model_name="request", + name="approved", + field=models.NullBooleanField(verbose_name="Approved?"), ), migrations.AlterField( - model_name='request', - name='reason_for_approval', - field=models.TextField(blank=True, null=True, verbose_name='Approval Notes'), + model_name="request", + name="reason_for_approval", + field=models.TextField( + blank=True, null=True, verbose_name="Approval Notes" + ), ), migrations.AlterField( - model_name='secret', - name='secret_type', - field=models.CharField(choices=[('recovery_key', 'Recovery Key'), ('password', 'Password')], default='recovery_key', max_length=256), + model_name="secret", + name="secret_type", + field=models.CharField( + choices=[("recovery_key", "Recovery Key"), ("password", "Password")], + default="recovery_key", + max_length=256, + ), ), migrations.AlterField( - model_name='request', - name='auth_user', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='auth_user', to=settings.AUTH_USER_MODEL), + model_name="request", + name="auth_user", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="auth_user", + to=settings.AUTH_USER_MODEL, + ), ), migrations.AlterField( - model_name='request', - name='secret', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='server.Secret'), + model_name="request", + name="secret", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, to="server.Secret" + ), ), migrations.AlterField( - model_name='computer', - name='computername', - field=models.CharField(max_length=200, verbose_name='Computer Name'), + model_name="computer", + name="computername", + field=models.CharField(max_length=200, verbose_name="Computer Name"), ), migrations.AlterField( - model_name='computer', - name='serial', - field=models.CharField(max_length=200, verbose_name='Serial Number'), + model_name="computer", + name="serial", + field=models.CharField(max_length=200, verbose_name="Serial Number"), ), migrations.AlterField( - model_name='computer', - name='username', - field=models.CharField(max_length=200, verbose_name='User Name'), + model_name="computer", + name="username", + field=models.CharField(max_length=200, verbose_name="User Name"), ), migrations.AlterField( - model_name='request', - name='approved', - field=models.NullBooleanField(verbose_name='Approved?'), + model_name="request", + name="approved", + field=models.NullBooleanField(verbose_name="Approved?"), ), migrations.AlterField( - model_name='request', - name='reason_for_approval', - field=models.TextField(blank=True, null=True, verbose_name='Approval Notes'), + model_name="request", + name="reason_for_approval", + field=models.TextField( + blank=True, null=True, verbose_name="Approval Notes" + ), ), migrations.AlterField( - model_name='secret', - name='secret_type', - field=models.CharField(choices=[('recovery_key', 'Recovery Key'), ('password', 'Password')], default='recovery_key', max_length=256), + model_name="secret", + name="secret_type", + field=models.CharField( + choices=[("recovery_key", "Recovery Key"), ("password", "Password")], + default="recovery_key", + max_length=256, + ), ), ] diff --git a/server/migrations/0006_auto_20150714_0821.py b/server/migrations/0006_auto_20150714_0821.py index 85e0ad8..bf51afa 100644 --- a/server/migrations/0006_auto_20150714_0821.py +++ b/server/migrations/0006_auto_20150714_0821.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import models, migrations + # import django_extensions.db.fields.encrypted diff --git a/server/models.py b/server/models.py index 9cf2c28..b8dac82 100644 --- a/server/models.py +++ b/server/models.py @@ -19,7 +19,7 @@ def __str__(self): class Meta: ordering = ["serial"] permissions = ( - ("can_approve", (u"Can approve requests to see encryption keys")), + ("can_approve", ("Can approve requests to see encryption keys")), ) diff --git a/server/views.py b/server/views.py index e5533f9..d954561 100644 --- a/server/views.py +++ b/server/views.py @@ -37,7 +37,9 @@ def cleanup(): def get_server_version(): current_dir = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), 'rb') as f: + with open( + os.path.join(os.path.dirname(current_dir), "fvserver", "version.plist"), "rb" + ) as f: version = plistlib.load(f) return version["version"]