Merge branch 'master' into guardian
# Conflicts: # Pipfile # Pipfile.lock # passbook/core/models.py
This commit is contained in:
commit
143a575369
|
@ -1,5 +1,5 @@
|
||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.6.3-beta
|
current_version = 0.6.4-beta
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||||
|
|
|
@ -27,7 +27,7 @@ create-base-image:
|
||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
script:
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/base.Dockerfile --destination docker.beryju.org/passbook/base:latest --destination docker.beryju.org/passbook/base:0.6.3-beta
|
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/base.Dockerfile --destination docker.beryju.org/passbook/base:latest
|
||||||
stage: build-base-image
|
stage: build-base-image
|
||||||
only:
|
only:
|
||||||
refs:
|
refs:
|
||||||
|
@ -41,7 +41,7 @@ build-dev-image:
|
||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
script:
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dev.Dockerfile --destination docker.beryju.org/passbook/dev:latest --destination docker.beryju.org/passbook/dev:0.6.3-beta
|
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dev.Dockerfile --destination docker.beryju.org/passbook/dev:latest
|
||||||
stage: build-dev-image
|
stage: build-dev-image
|
||||||
only:
|
only:
|
||||||
refs:
|
refs:
|
||||||
|
@ -70,13 +70,13 @@ migrations:
|
||||||
# services:
|
# services:
|
||||||
# - postgres:latest
|
# - postgres:latest
|
||||||
# - redis:latest
|
# - redis:latest
|
||||||
# pylint:
|
pylint:
|
||||||
# script:
|
script:
|
||||||
# - pylint passbook
|
- pylint passbook
|
||||||
# stage: test
|
stage: test
|
||||||
# services:
|
services:
|
||||||
# - postgres:latest
|
- postgres:latest
|
||||||
# - redis:latest
|
- redis:latest
|
||||||
coverage:
|
coverage:
|
||||||
script:
|
script:
|
||||||
- coverage run manage.py test
|
- coverage run manage.py test
|
||||||
|
@ -95,7 +95,7 @@ build-passbook-server:
|
||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
script:
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.beryju.org/passbook/server:latest --destination docker.beryju.org/passbook/server:0.6.3-beta
|
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.beryju.org/passbook/server:latest --destination docker.beryju.org/passbook/server:0.6.4-beta
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
- /^version/.*$/
|
- /^version/.*$/
|
||||||
|
@ -107,7 +107,7 @@ build-passbook-static:
|
||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
script:
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/static.Dockerfile --destination docker.beryju.org/passbook/static:latest --destination docker.beryju.org/passbook/static:0.6.3-beta
|
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/static.Dockerfile --destination docker.beryju.org/passbook/static:latest --destination docker.beryju.org/passbook/static:0.6.4-beta
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
- /^version/.*$/
|
- /^version/.*$/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM docker.beryju.org/passbook/base:latest
|
FROM docker.beryju.org/passbook/base:latest
|
||||||
|
|
||||||
COPY --chown=passbook:passbook ./passbook/ /app/passbook
|
COPY ./passbook/ /app/passbook
|
||||||
COPY ./manage.py /app/
|
COPY ./manage.py /app/
|
||||||
COPY ./docker/uwsgi.ini /app/
|
COPY ./docker/uwsgi.ini /app/
|
||||||
|
|
||||||
|
|
6
Pipfile
6
Pipfile
|
@ -35,18 +35,18 @@ service_identity = "*"
|
||||||
signxml = "*"
|
signxml = "*"
|
||||||
urllib3 = {extras = ["secure"],version = "*"}
|
urllib3 = {extras = ["secure"],version = "*"}
|
||||||
structlog = "*"
|
structlog = "*"
|
||||||
|
pyuwsgi = "*"
|
||||||
django-guardian = "*"
|
django-guardian = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
astroid = "==2.2.5"
|
|
||||||
coverage = "*"
|
coverage = "*"
|
||||||
isort = "*"
|
isort = "*"
|
||||||
pylint = "==2.3.1"
|
pylint = "==2.3.1"
|
||||||
pylint-django = "==2.0.10"
|
pylint-django = "*"
|
||||||
prospector = "==1.1.7"
|
prospector = "*"
|
||||||
django-debug-toolbar = "*"
|
django-debug-toolbar = "*"
|
||||||
bumpversion = "*"
|
bumpversion = "*"
|
||||||
unittest-xml-reporting = "*"
|
unittest-xml-reporting = "*"
|
||||||
|
|
39
Pipfile.lock
generated
39
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "1636ead76bcc61736245f5255a6dfafbf261c3b37b1a2b2665db50919b4cb1ea"
|
"sha256": "587f6d2958f73bf9ae1026c03d123b66937fa642ccd2877f86c4c9b453d15fae"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -101,10 +101,10 @@
|
||||||
},
|
},
|
||||||
"cheroot": {
|
"cheroot": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:709259ea832932fb4e1c040b87836a260d386155098c7e138fc317937763e7ae",
|
"sha256:3ff64073efa35b39d5e107410f5c79664dc8c6c5990651e970740c80ab8878a8",
|
||||||
"sha256:abba64f5f0d09b3b8bddf98fa18df1176cd83728b220a995e061c1a766e20a45"
|
"sha256:d523a1525258730026aa35b86c8c47c8d0e3892fb89f0f39157d4b32a50edf05"
|
||||||
],
|
],
|
||||||
"version": "==8.0.0"
|
"version": "==8.1.0"
|
||||||
},
|
},
|
||||||
"cherrypy": {
|
"cherrypy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -572,6 +572,36 @@
|
||||||
],
|
],
|
||||||
"version": "==2019.3"
|
"version": "==2019.3"
|
||||||
},
|
},
|
||||||
|
"pyuwsgi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:15a4626740753b0d0dfeeac7d367f9b2e89ab6af16c195927e60f75359fc1bbc",
|
||||||
|
"sha256:24c40c3b889eb9f283d43feffbc0f7c7fc024e914451425156ddb68af3df1e71",
|
||||||
|
"sha256:393737bd43a7e38f0a4a1601a37a69c4bf893635b37665ff958170fdb604fdb7",
|
||||||
|
"sha256:5a08308f87e639573c1efaa5966a6d04410cd45a73c4586a932fe3ee4b56369d",
|
||||||
|
"sha256:5f4b36c0dbb9931c4da8008aa423158be596e3b4a23cec95a958631603a94e45",
|
||||||
|
"sha256:7c31794f71bbd0ccf542cab6bddf38aa69e84e31ae0f9657a2e18ebdc150c01a",
|
||||||
|
"sha256:802ec6dad4b6707b934370926ec1866603abe31ba03c472f56149001b3533ba1",
|
||||||
|
"sha256:814d73d4569add69a6c19bb4a27cd5adb72b196e5e080caed17dbda740402072",
|
||||||
|
"sha256:829299cd117cf8abe837796bf587e61ce6bfe18423a3a1c510c21e9825789c2c",
|
||||||
|
"sha256:85f2210ceae5f48b7d8fad2240d831f4b890cac85cd98ca82683ac6aa481dfc8",
|
||||||
|
"sha256:861c94442b28cd64af033e88e0f63c66dbd5609f67952dc18694098b47a43f3a",
|
||||||
|
"sha256:957bc6316ffc8463795d56d9953d58e7f32aa5aad1c5ac80bc45c69f3299961e",
|
||||||
|
"sha256:9760c3f56fb5f15852d163429096600906478e9ed2c189a52f2bb21d8a2a986c",
|
||||||
|
"sha256:a4b24703ea818196d0be1dc64b3b57b79c67e8dee0cfa207a4216220912035a7",
|
||||||
|
"sha256:ad7f4968c1ddbf139a306d9b075360d959cc554d994ba5e1f512af9a40e62357",
|
||||||
|
"sha256:b1127d34b90f74faf1707718c57a4193ac028b9f4aec0238638983132297d456",
|
||||||
|
"sha256:bcb04d6ec644b3e08d03c64851e06edd7110489261e50627a4bcadf66ff6920e",
|
||||||
|
"sha256:bebfebb9ee83d7cf37668bf54275b677b7ae283e84a944f9f3ac6a4b66f95d4b",
|
||||||
|
"sha256:c29892dafc65a8b6eb95823fa4bac7754ca3fd1c28ab8d2a973289531b340a27",
|
||||||
|
"sha256:cb296b50b51ba022b0090b28d032ff1dd395a6db03672b65a39e83532edad527",
|
||||||
|
"sha256:ce777ebdf49ce736fc04abf555b5c41ab3f130127543a689dcf8d4871cd18fe4",
|
||||||
|
"sha256:d8b4bf930b6a19bc9ee982b9163d948c87501ad91b71516924e8ed25fe85d2ee",
|
||||||
|
"sha256:e2a420f2c4d35f3ec0b7e752a80d7bd385e2c5a64f67c05f2d2d74230e3114b6",
|
||||||
|
"sha256:fed899ce96f4f2b4d1b9f338dd145a4040ee1d8a5152213af0dd8d4a4d36e9fe"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.0.18.post0"
|
||||||
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",
|
"sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",
|
||||||
|
@ -745,7 +775,6 @@
|
||||||
"sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4",
|
"sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4",
|
||||||
"sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"
|
"sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
|
||||||
"version": "==2.2.5"
|
"version": "==2.2.5"
|
||||||
},
|
},
|
||||||
"autopep8": {
|
"autopep8": {
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
FROM python:3.7-slim-stretch
|
FROM python:3.7-slim-buster as locker
|
||||||
|
|
||||||
COPY ./Pipfile /app/
|
COPY ./Pipfile /app/
|
||||||
COPY ./Pipfile.lock /app/
|
COPY ./Pipfile.lock /app/
|
||||||
|
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN pip install pipenv && \
|
||||||
apt-get install -y --no-install-recommends build-essential && \
|
pipenv lock -r > requirements.txt && \
|
||||||
pip install pipenv uwsgi --no-cache-dir && \
|
pipenv lock -rd > requirements-dev.txt
|
||||||
apt-get remove -y --purge build-essential && \
|
|
||||||
apt-get autoremove -y --purge && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN pipenv lock -r > requirements.txt && \
|
FROM python:3.7-slim-buster
|
||||||
pipenv --rm && \
|
|
||||||
pip install -r requirements.txt --no-cache-dir && \
|
COPY --from=locker /app/requirements.txt /app/
|
||||||
|
|
||||||
|
WORKDIR /app/
|
||||||
|
|
||||||
|
RUN pip install -r requirements.txt --no-cache-dir && \
|
||||||
adduser --system --no-create-home --uid 1000 --group --home /app passbook
|
adduser --system --no-create-home --uid 1000 --group --home /app passbook
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
FROM docker.beryju.org/passbook/base:latest
|
FROM docker.beryju.org/passbook/base:latest
|
||||||
|
|
||||||
RUN pipenv lock --dev -r > requirements-dev.txt && \
|
RUN pip install -r /app/requirements-dev.txt --no-cache-dir
|
||||||
pipenv --rm && \
|
|
||||||
pip install -r /app/requirements-dev.txt --no-cache-dir
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ services:
|
||||||
- -E
|
- -E
|
||||||
- -B
|
- -B
|
||||||
- -A=passbook.root.celery
|
- -A=passbook.root.celery
|
||||||
|
- -s=/tmp/celerybeat-schedule
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -39,7 +39,7 @@ http {
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_types application/javascript image/* text/css;
|
gzip_types application/javascript image/* text/css;
|
||||||
gunzip on;
|
gunzip on;
|
||||||
add_header X-passbook-Version 0.6.3-beta;
|
add_header X-passbook-Version 0.6.4-beta;
|
||||||
add_header Vary X-passbook-Version;
|
add_header Vary X-passbook-Version;
|
||||||
root /data/;
|
root /data/;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
appVersion: "0.6.3-beta"
|
appVersion: "0.6.4-beta"
|
||||||
description: A Helm chart for passbook.
|
description: A Helm chart for passbook.
|
||||||
name: passbook
|
name: passbook
|
||||||
version: "0.6.3-beta"
|
version: "0.6.4-beta"
|
||||||
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
|
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
|
||||||
|
|
|
@ -36,6 +36,7 @@ spec:
|
||||||
- -E
|
- -E
|
||||||
- -B
|
- -B
|
||||||
- -A=passbook.root.celery
|
- -A=passbook.root.celery
|
||||||
|
- -s=/tmp/celerybeat-schedule
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /etc/passbook
|
- mountPath: /etc/passbook
|
||||||
name: config-volume
|
name: config-volume
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# This is a YAML-formatted file.
|
# This is a YAML-formatted file.
|
||||||
# Declare variables to be passed into your templates.
|
# Declare variables to be passed into your templates.
|
||||||
image:
|
image:
|
||||||
tag: 0.6.3-beta
|
tag: 0.6.4-beta
|
||||||
|
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
"""passbook"""
|
"""passbook"""
|
||||||
__version__ = '0.6.3-beta'
|
__version__ = '0.6.4-beta'
|
||||||
|
|
18
passbook/core/migrations/0002_nonce_description.py
Normal file
18
passbook/core/migrations/0002_nonce_description.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.6 on 2019-10-10 11:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('passbook_core', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='nonce',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(blank=True, default=''),
|
||||||
|
),
|
||||||
|
]
|
|
@ -77,6 +77,7 @@ class Provider(models.Model):
|
||||||
return getattr(self, 'name')
|
return getattr(self, 'name')
|
||||||
return super().__str__()
|
return super().__str__()
|
||||||
|
|
||||||
|
|
||||||
class PolicyModel(UUIDModel, CreatedUpdatedModel):
|
class PolicyModel(UUIDModel, CreatedUpdatedModel):
|
||||||
"""Base model which can have policies applied to it"""
|
"""Base model which can have policies applied to it"""
|
||||||
|
|
||||||
|
@ -262,21 +263,29 @@ class Invitation(UUIDModel):
|
||||||
verbose_name = _('Invitation')
|
verbose_name = _('Invitation')
|
||||||
verbose_name_plural = _('Invitations')
|
verbose_name_plural = _('Invitations')
|
||||||
|
|
||||||
|
|
||||||
class Nonce(UUIDModel):
|
class Nonce(UUIDModel):
|
||||||
"""One-time link for password resets/sign-up-confirmations"""
|
"""One-time link for password resets/sign-up-confirmations"""
|
||||||
|
|
||||||
expires = models.DateTimeField(default=default_nonce_duration)
|
expires = models.DateTimeField(default=default_nonce_duration)
|
||||||
user = models.ForeignKey('User', on_delete=models.CASCADE)
|
user = models.ForeignKey('User', on_delete=models.CASCADE)
|
||||||
expiring = models.BooleanField(default=True)
|
expiring = models.BooleanField(default=True)
|
||||||
|
description = models.TextField(default='', blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_expired(self) -> bool:
|
||||||
|
"""Check if nonce is expired yet."""
|
||||||
|
return now() > self.expires
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Nonce f{self.uuid.hex} (expires={self.expires})"
|
return f"Nonce f{self.uuid.hex} {self.description} (expires={self.expires})"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _('Nonce')
|
verbose_name = _('Nonce')
|
||||||
verbose_name_plural = _('Nonces')
|
verbose_name_plural = _('Nonces')
|
||||||
|
|
||||||
|
|
||||||
class PropertyMapping(UUIDModel):
|
class PropertyMapping(UUIDModel):
|
||||||
"""User-defined key -> x mapping which can be used by providers to expose extra data."""
|
"""User-defined key -> x mapping which can be used by providers to expose extra data."""
|
||||||
|
|
||||||
|
|
0
passbook/recovery/__init__.py
Normal file
0
passbook/recovery/__init__.py
Normal file
11
passbook/recovery/apps.py
Normal file
11
passbook/recovery/apps.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"""passbook Recovery app config"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PassbookRecoveryConfig(AppConfig):
|
||||||
|
"""passbook Recovery app config"""
|
||||||
|
|
||||||
|
name = 'passbook.recovery'
|
||||||
|
label = 'passbook_recovery'
|
||||||
|
verbose_name = 'passbook Recovery'
|
||||||
|
mountpoint = 'recovery/'
|
0
passbook/recovery/management/__init__.py
Normal file
0
passbook/recovery/management/__init__.py
Normal file
0
passbook/recovery/management/commands/__init__.py
Normal file
0
passbook/recovery/management/commands/__init__.py
Normal file
46
passbook/recovery/management/commands/create_recovery_key.py
Normal file
46
passbook/recovery/management/commands/create_recovery_key.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
"""passbook recovery createkey command"""
|
||||||
|
from datetime import timedelta
|
||||||
|
from getpass import getuser
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from structlog import get_logger
|
||||||
|
|
||||||
|
from passbook.core.models import Nonce, User
|
||||||
|
from passbook.lib.config import CONFIG
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
"""Create Nonce used to recover access"""
|
||||||
|
|
||||||
|
help = _('Create a Key which can be used to restore access to passbook.')
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('duration', default=1, action='store',
|
||||||
|
help='How long the token is valid for (in years).')
|
||||||
|
parser.add_argument('user', action='store',
|
||||||
|
help='Which user the Token gives access to.')
|
||||||
|
|
||||||
|
def get_url(self, nonce: Nonce) -> str:
|
||||||
|
"""Get full recovery link"""
|
||||||
|
path = reverse('passbook_recovery:use-nonce', kwargs={'uuid': str(nonce.uuid)})
|
||||||
|
return f"https://{CONFIG.y('domain')}{path}"
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
"""Create Nonce used to recover access"""
|
||||||
|
duration = int(options.get('duration', 1))
|
||||||
|
delta = timedelta(days=duration * 365.2425)
|
||||||
|
_now = now()
|
||||||
|
expiry = _now + delta
|
||||||
|
user = User.objects.get(username=options.get('user'))
|
||||||
|
nonce = Nonce.objects.create(
|
||||||
|
expires=expiry,
|
||||||
|
user=user,
|
||||||
|
description=f'Recovery Nonce generated by {getuser()} on {_now}')
|
||||||
|
self.stdout.write((f"Store this link safely, as it will allow"
|
||||||
|
f" anyone to access passbook as {user}."))
|
||||||
|
self.stdout.write(self.get_url(nonce))
|
9
passbook/recovery/urls.py
Normal file
9
passbook/recovery/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
"""recovery views"""
|
||||||
|
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from passbook.recovery.views import UseNonceView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('use-nonce/<uuid:uuid>/', UseNonceView.as_view(), name='use-nonce'),
|
||||||
|
]
|
24
passbook/recovery/views.py
Normal file
24
passbook/recovery/views.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
"""recovery views"""
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth import login
|
||||||
|
from django.http import Http404, HttpRequest, HttpResponse
|
||||||
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from django.views import View
|
||||||
|
|
||||||
|
from passbook.core.models import Nonce
|
||||||
|
|
||||||
|
|
||||||
|
class UseNonceView(View):
|
||||||
|
"""Use nonce to login"""
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, uuid: str) -> HttpResponse:
|
||||||
|
"""Check if nonce exists, log user in and delete nonce."""
|
||||||
|
nonce: Nonce = get_object_or_404(Nonce, pk=uuid)
|
||||||
|
if nonce.is_expired:
|
||||||
|
nonce.delete()
|
||||||
|
raise Http404
|
||||||
|
login(request, nonce.user, backend='django.contrib.auth.backends.ModelBackend')
|
||||||
|
nonce.delete()
|
||||||
|
messages.warning(request, _("Used recovery-link to authenticate."))
|
||||||
|
return redirect('passbook_core:overview')
|
|
@ -74,6 +74,7 @@ INSTALLED_APPS = [
|
||||||
'passbook.api.apps.PassbookAPIConfig',
|
'passbook.api.apps.PassbookAPIConfig',
|
||||||
'passbook.lib.apps.PassbookLibConfig',
|
'passbook.lib.apps.PassbookLibConfig',
|
||||||
'passbook.audit.apps.PassbookAuditConfig',
|
'passbook.audit.apps.PassbookAuditConfig',
|
||||||
|
'passbook.recovery.apps.PassbookRecoveryConfig',
|
||||||
|
|
||||||
'passbook.sources.ldap.apps.PassbookSourceLDAPConfig',
|
'passbook.sources.ldap.apps.PassbookSourceLDAPConfig',
|
||||||
'passbook.sources.oauth.apps.PassbookSourceOAuthConfig',
|
'passbook.sources.oauth.apps.PassbookSourceOAuthConfig',
|
||||||
|
|
0
passbook/sources/__init__.py
Normal file
0
passbook/sources/__init__.py
Normal file
Reference in a new issue