@@ -10,12 +10,14 @@ from django.db.models import Count | |||
class UserCreationForm(forms.ModelForm): | |||
password1 = forms.CharField(label='Password', widget=forms.PasswordInput) | |||
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) | |||
password1 = forms.CharField(label="Password", widget=forms.PasswordInput) | |||
password2 = forms.CharField( | |||
label="Password confirmation", widget=forms.PasswordInput | |||
) | |||
class Meta: | |||
model = LessPassUser | |||
fields = ('email',) | |||
fields = ("email",) | |||
def clean_password2(self): | |||
password1 = self.cleaned_data.get("password1") | |||
@@ -37,7 +39,7 @@ class UserChangeForm(forms.ModelForm): | |||
class Meta: | |||
model = LessPassUser | |||
fields = ('email', 'password', 'is_active', 'is_admin') | |||
fields = ("email", "password", "is_active", "is_admin") | |||
def clean_password(self): | |||
return self.initial["password"] | |||
@@ -47,36 +49,36 @@ class LessPassUserAdmin(BaseUserAdmin): | |||
form = UserChangeForm | |||
add_form = UserCreationForm | |||
list_display = ('email', 'is_admin', 'column_passwords_count') | |||
list_filter = ('is_admin', 'is_active') | |||
list_display = ("email", "is_admin", "column_passwords_count") | |||
list_filter = ("is_admin", "is_active") | |||
fieldsets = ( | |||
(None, {'fields': ('email', 'password')}), | |||
('Permissions', {'fields': ('is_admin',)}), | |||
(None, {"fields": ("email", "password")}), | |||
("Permissions", {"fields": ("is_admin",)}), | |||
) | |||
add_fieldsets = ( | |||
(None, { | |||
'classes': ('wide',), | |||
'fields': ('email', 'password1', 'password2')} | |||
), | |||
(None, {"classes": ("wide",), "fields": ("email", "password1", "password2")}), | |||
) | |||
search_fields = ('email',) | |||
ordering = ('email',) | |||
search_fields = ("email",) | |||
ordering = ("email",) | |||
filter_horizontal = () | |||
def get_queryset(self, request): | |||
return models.LessPassUser.objects.annotate(passwords_count=Count('passwords')) | |||
return models.LessPassUser.objects.annotate(passwords_count=Count("passwords")) | |||
def column_passwords_count(self, instance): | |||
return instance.passwords_count | |||
column_passwords_count.short_description = 'Password count' | |||
column_passwords_count.admin_order_field = 'passwords_count' | |||
column_passwords_count.short_description = "Password count" | |||
column_passwords_count.admin_order_field = "passwords_count" | |||
class PasswordAdmin(admin.ModelAdmin): | |||
list_display = ('id', 'user',) | |||
search_fields = ('user__email',) | |||
ordering = ('user',) | |||
list_display = ( | |||
"id", | |||
"user", | |||
) | |||
search_fields = ("user__email",) | |||
ordering = ("user",) | |||
admin.site.register(models.Password, PasswordAdmin) | |||
@@ -2,4 +2,4 @@ from django.apps import AppConfig | |||
class ApiConfig(AppConfig): | |||
name = 'api' | |||
name = "api" |
@@ -12,62 +12,107 @@ class Migration(migrations.Migration): | |||
initial = True | |||
dependencies = [ | |||
] | |||
dependencies = [] | |||
operations = [ | |||
migrations.CreateModel( | |||
name='LessPassUser', | |||
name="LessPassUser", | |||
fields=[ | |||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |||
('password', models.CharField(max_length=128, verbose_name='password')), | |||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), | |||
('email', models.EmailField(max_length=255, unique=True, verbose_name='email address')), | |||
('is_active', models.BooleanField(default=True)), | |||
('is_admin', models.BooleanField(default=False)), | |||
( | |||
"id", | |||
models.AutoField( | |||
auto_created=True, | |||
primary_key=True, | |||
serialize=False, | |||
verbose_name="ID", | |||
), | |||
), | |||
("password", models.CharField(max_length=128, verbose_name="password")), | |||
( | |||
"last_login", | |||
models.DateTimeField( | |||
blank=True, null=True, verbose_name="last login" | |||
), | |||
), | |||
( | |||
"email", | |||
models.EmailField( | |||
max_length=255, unique=True, verbose_name="email address" | |||
), | |||
), | |||
("is_active", models.BooleanField(default=True)), | |||
("is_admin", models.BooleanField(default=False)), | |||
], | |||
options={ | |||
'verbose_name_plural': 'Users', | |||
"verbose_name_plural": "Users", | |||
}, | |||
), | |||
migrations.CreateModel( | |||
name='Entry', | |||
name="Entry", | |||
fields=[ | |||
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), | |||
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), | |||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), | |||
('login', models.CharField(default='', max_length=255)), | |||
('site', models.CharField(default='', max_length=255)), | |||
('title', models.CharField(blank=True, max_length=255, null=True)), | |||
('username', models.CharField(blank=True, max_length=255, null=True)), | |||
('email', models.EmailField(blank=True, max_length=254, null=True)), | |||
('description', models.TextField(blank=True, null=True)), | |||
('url', models.URLField(blank=True, null=True)), | |||
( | |||
"created", | |||
models.DateTimeField(auto_now_add=True, verbose_name="created"), | |||
), | |||
( | |||
"modified", | |||
models.DateTimeField(auto_now=True, verbose_name="modified"), | |||
), | |||
( | |||
"id", | |||
models.UUIDField( | |||
default=uuid.uuid4, | |||
editable=False, | |||
primary_key=True, | |||
serialize=False, | |||
), | |||
), | |||
("login", models.CharField(default="", max_length=255)), | |||
("site", models.CharField(default="", max_length=255)), | |||
("title", models.CharField(blank=True, max_length=255, null=True)), | |||
("username", models.CharField(blank=True, max_length=255, null=True)), | |||
("email", models.EmailField(blank=True, max_length=254, null=True)), | |||
("description", models.TextField(blank=True, null=True)), | |||
("url", models.URLField(blank=True, null=True)), | |||
], | |||
options={ | |||
'verbose_name_plural': 'Entries', | |||
"verbose_name_plural": "Entries", | |||
}, | |||
), | |||
migrations.CreateModel( | |||
name='PasswordInfo', | |||
name="PasswordInfo", | |||
fields=[ | |||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), | |||
('counter', models.IntegerField(default=1)), | |||
('settings', models.TextField()), | |||
('length', models.IntegerField(default=12)), | |||
( | |||
"id", | |||
models.UUIDField( | |||
default=uuid.uuid4, | |||
editable=False, | |||
primary_key=True, | |||
serialize=False, | |||
), | |||
), | |||
("counter", models.IntegerField(default=1)), | |||
("settings", models.TextField()), | |||
("length", models.IntegerField(default=12)), | |||
], | |||
options={ | |||
'verbose_name_plural': 'Password info', | |||
"verbose_name_plural": "Password info", | |||
}, | |||
), | |||
migrations.AddField( | |||
model_name='entry', | |||
name='password', | |||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.PasswordInfo'), | |||
model_name="entry", | |||
name="password", | |||
field=models.ForeignKey( | |||
on_delete=django.db.models.deletion.CASCADE, to="api.PasswordInfo" | |||
), | |||
), | |||
migrations.AddField( | |||
model_name='entry', | |||
name='user', | |||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='entries', to=settings.AUTH_USER_MODEL), | |||
model_name="entry", | |||
name="user", | |||
field=models.ForeignKey( | |||
on_delete=django.db.models.deletion.CASCADE, | |||
related_name="entries", | |||
to=settings.AUTH_USER_MODEL, | |||
), | |||
), | |||
] |
@@ -11,28 +11,49 @@ import uuid | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0001_initial'), | |||
("api", "0001_initial"), | |||
] | |||
operations = [ | |||
migrations.CreateModel( | |||
name='Password', | |||
name="Password", | |||
fields=[ | |||
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), | |||
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), | |||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), | |||
('login', models.CharField(blank=True, max_length=255, null=True)), | |||
('site', models.CharField(blank=True, max_length=255, null=True)), | |||
('lowercase', models.BooleanField(default=True)), | |||
('uppercase', models.BooleanField(default=True)), | |||
('symbols', models.BooleanField(default=True)), | |||
('numbers', models.BooleanField(default=True)), | |||
('counter', models.IntegerField(default=1)), | |||
('length', models.IntegerField(default=12)), | |||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='passwords', to=settings.AUTH_USER_MODEL)), | |||
( | |||
"created", | |||
models.DateTimeField(auto_now_add=True, verbose_name="created"), | |||
), | |||
( | |||
"modified", | |||
models.DateTimeField(auto_now=True, verbose_name="modified"), | |||
), | |||
( | |||
"id", | |||
models.UUIDField( | |||
default=uuid.uuid4, | |||
editable=False, | |||
primary_key=True, | |||
serialize=False, | |||
), | |||
), | |||
("login", models.CharField(blank=True, max_length=255, null=True)), | |||
("site", models.CharField(blank=True, max_length=255, null=True)), | |||
("lowercase", models.BooleanField(default=True)), | |||
("uppercase", models.BooleanField(default=True)), | |||
("symbols", models.BooleanField(default=True)), | |||
("numbers", models.BooleanField(default=True)), | |||
("counter", models.IntegerField(default=1)), | |||
("length", models.IntegerField(default=12)), | |||
( | |||
"user", | |||
models.ForeignKey( | |||
on_delete=django.db.models.deletion.CASCADE, | |||
related_name="passwords", | |||
to=settings.AUTH_USER_MODEL, | |||
), | |||
), | |||
], | |||
options={ | |||
'abstract': False, | |||
"abstract": False, | |||
}, | |||
), | |||
] |
@@ -11,14 +11,23 @@ from api import models | |||
def create_password_with(entry): | |||
settings = json.dumps(entry.password.settings) | |||
lowercase = 'lowercase' in settings | |||
uppercase = 'uppercase' in settings | |||
symbols = 'symbols' in settings | |||
numbers = 'numbers' in settings | |||
lowercase = "lowercase" in settings | |||
uppercase = "uppercase" in settings | |||
symbols = "symbols" in settings | |||
numbers = "numbers" in settings | |||
user = models.LessPassUser.objects.get(id=entry.user.id) | |||
models.Password.objects.create(id=entry.id, site=entry.site, login=entry.login, user=user, | |||
lowercase=lowercase, uppercase=uppercase, symbols=symbols, numbers=numbers, | |||
counter=entry.password.counter, length=entry.password.length) | |||
models.Password.objects.create( | |||
id=entry.id, | |||
site=entry.site, | |||
login=entry.login, | |||
user=user, | |||
lowercase=lowercase, | |||
uppercase=uppercase, | |||
symbols=symbols, | |||
numbers=numbers, | |||
counter=entry.password.counter, | |||
length=entry.password.length, | |||
) | |||
def mv_entries_to_password(apps, schema_editor): | |||
@@ -29,7 +38,7 @@ def mv_entries_to_password(apps, schema_editor): | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0002_password'), | |||
("api", "0002_password"), | |||
] | |||
operations = [ | |||
@@ -8,22 +8,22 @@ from django.db import migrations | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0003_mv_entries_to_password'), | |||
("api", "0003_mv_entries_to_password"), | |||
] | |||
operations = [ | |||
migrations.RemoveField( | |||
model_name='entry', | |||
name='password', | |||
model_name="entry", | |||
name="password", | |||
), | |||
migrations.RemoveField( | |||
model_name='entry', | |||
name='user', | |||
model_name="entry", | |||
name="user", | |||
), | |||
migrations.DeleteModel( | |||
name='Entry', | |||
name="Entry", | |||
), | |||
migrations.DeleteModel( | |||
name='PasswordInfo', | |||
name="PasswordInfo", | |||
), | |||
] |
@@ -8,13 +8,13 @@ from django.db import migrations, models | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0004_remove_entries_password_info_models'), | |||
("api", "0004_remove_entries_password_info_models"), | |||
] | |||
operations = [ | |||
migrations.AddField( | |||
model_name='password', | |||
name='version', | |||
model_name="password", | |||
name="version", | |||
field=models.IntegerField(default=1), | |||
), | |||
] |
@@ -8,18 +8,18 @@ from django.db import migrations, models | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0005_password_version'), | |||
("api", "0005_password_version"), | |||
] | |||
operations = [ | |||
migrations.AlterField( | |||
model_name='password', | |||
name='length', | |||
model_name="password", | |||
name="length", | |||
field=models.IntegerField(default=16), | |||
), | |||
migrations.AlterField( | |||
model_name='password', | |||
name='version', | |||
model_name="password", | |||
name="version", | |||
field=models.IntegerField(default=2), | |||
), | |||
] |
@@ -6,13 +6,13 @@ from django.db import migrations, models | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0006_change_default_password_profile'), | |||
("api", "0006_change_default_password_profile"), | |||
] | |||
operations = [ | |||
migrations.AddField( | |||
model_name='lesspassuser', | |||
name='key', | |||
model_name="lesspassuser", | |||
name="key", | |||
field=models.TextField(null=True), | |||
), | |||
] |
@@ -9,21 +9,42 @@ import uuid | |||
class Migration(migrations.Migration): | |||
dependencies = [ | |||
('api', '0007_lesspassuser_key'), | |||
("api", "0007_lesspassuser_key"), | |||
] | |||
operations = [ | |||
migrations.CreateModel( | |||
name='EncryptedPasswordProfile', | |||
name="EncryptedPasswordProfile", | |||
fields=[ | |||
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), | |||
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), | |||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), | |||
('password_profile', models.TextField()), | |||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='encrypted_password_profiles', to=settings.AUTH_USER_MODEL)), | |||
( | |||
"created", | |||
models.DateTimeField(auto_now_add=True, verbose_name="created"), | |||
), | |||
( | |||
"modified", | |||
models.DateTimeField(auto_now=True, verbose_name="modified"), | |||
), | |||
( | |||
"id", | |||
models.UUIDField( | |||
default=uuid.uuid4, | |||
editable=False, | |||
primary_key=True, | |||
serialize=False, | |||
), | |||
), | |||
("password_profile", models.TextField()), | |||
( | |||
"user", | |||
models.ForeignKey( | |||
on_delete=django.db.models.deletion.CASCADE, | |||
related_name="encrypted_password_profiles", | |||
to=settings.AUTH_USER_MODEL, | |||
), | |||
), | |||
], | |||
options={ | |||
'abstract': False, | |||
"abstract": False, | |||
}, | |||
), | |||
] |
@@ -40,7 +40,9 @@ class EncryptedPasswordProfileSerializer(serializers.ModelSerializer): | |||
def create(self, validated_data): | |||
user = self.context["request"].user | |||
return models.EncryptedPasswordProfile.objects.create(user=user, **validated_data) | |||
return models.EncryptedPasswordProfile.objects.create( | |||
user=user, **validated_data | |||
) | |||
class BackwardCompatibleTokenObtainPairSerializer(TokenObtainPairSerializer): | |||
@@ -60,11 +60,12 @@ class OldLoginTestCase(APITestCase): | |||
"password": "correct horse battery staple", | |||
} | |||
request = self.client.post("/api/tokens/auth/", data) | |||
headers = {"HTTP_AUTHORIZATION": "JWT {token}".format(token=request.data["token"])} | |||
headers = { | |||
"HTTP_AUTHORIZATION": "JWT {token}".format(token=request.data["token"]) | |||
} | |||
request = self.client.get("/api/passwords/", **headers) | |||
self.assertEqual(request.status_code, 200) | |||
self.assertEqual(request.data["results"][0]['login'], password.login) | |||
self.assertEqual(request.data["results"][0]["login"], password.login) | |||
def test_nrt_get_passwords_with_bearer(self): | |||
user = factories.UserFactory( | |||
@@ -76,7 +77,9 @@ class OldLoginTestCase(APITestCase): | |||
"password": "correct horse battery staple", | |||
} | |||
request = self.client.post("/api/auth/jwt/create/", data) | |||
headers = {"HTTP_AUTHORIZATION": "Bearer {token}".format(token=request.data["access"])} | |||
headers = { | |||
"HTTP_AUTHORIZATION": "Bearer {token}".format(token=request.data["access"]) | |||
} | |||
request = self.client.get("/api/passwords/", **headers) | |||
self.assertEqual(request.status_code, 200) | |||
self.assertEqual(request.data["results"][0]['login'], password.login) | |||
self.assertEqual(request.data["results"][0]["login"], password.login) |
@@ -6,7 +6,7 @@ from api.tests import factories | |||
class LogoutPasswordsTestCase(APITestCase): | |||
def test_get_passwords_401(self): | |||
response = self.client.get('/api/passwords/') | |||
response = self.client.get("/api/passwords/") | |||
self.assertEqual(401, response.status_code) | |||
@@ -17,31 +17,31 @@ class LoginPasswordsTestCase(APITestCase): | |||
self.client.force_authenticate(user=self.user) | |||
def test_get_empty_passwords(self): | |||
request = self.client.get('/api/passwords/') | |||
self.assertEqual(0, len(request.data['results'])) | |||
request = self.client.get("/api/passwords/") | |||
self.assertEqual(0, len(request.data["results"])) | |||
def test_retrieve_its_own_passwords(self): | |||
password = factories.PasswordFactory(user=self.user) | |||
request = self.client.get('/api/passwords/') | |||
self.assertEqual(1, len(request.data['results'])) | |||
self.assertEqual(password.site, request.data['results'][0]['site']) | |||
request = self.client.get("/api/passwords/") | |||
self.assertEqual(1, len(request.data["results"])) | |||
self.assertEqual(password.site, request.data["results"][0]["site"]) | |||
def test_cant_retrieve_other_passwords(self): | |||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | |||
request = self.client.get('/api/passwords/%s/' % not_my_password.id) | |||
request = self.client.get("/api/passwords/%s/" % not_my_password.id) | |||
self.assertEqual(404, request.status_code) | |||
def test_delete_its_own_passwords(self): | |||
password = factories.PasswordFactory(user=self.user) | |||
self.assertEqual(1, models.Password.objects.all().count()) | |||
request = self.client.delete('/api/passwords/%s/' % password.id) | |||
request = self.client.delete("/api/passwords/%s/" % password.id) | |||
self.assertEqual(204, request.status_code) | |||
self.assertEqual(0, models.Password.objects.all().count()) | |||
def test_cant_delete_other_password(self): | |||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | |||
self.assertEqual(1, models.Password.objects.all().count()) | |||
request = self.client.delete('/api/passwords/%s/' % not_my_password.id) | |||
request = self.client.delete("/api/passwords/%s/" % not_my_password.id) | |||
self.assertEqual(404, request.status_code) | |||
self.assertEqual(1, models.Password.objects.all().count()) | |||
@@ -54,10 +54,10 @@ class LoginPasswordsTestCase(APITestCase): | |||
"number": True, | |||
"symbol": True, | |||
"counter": 1, | |||
"length": 12 | |||
"length": 12, | |||
} | |||
self.assertEqual(0, models.Password.objects.count()) | |||
self.client.post('/api/passwords/', password) | |||
self.client.post("/api/passwords/", password) | |||
self.assertEqual(1, models.Password.objects.count()) | |||
def test_create_password_v2(self): | |||
@@ -70,14 +70,14 @@ class LoginPasswordsTestCase(APITestCase): | |||
"symbol": True, | |||
"counter": 1, | |||
"length": 12, | |||
"version": 2 | |||
"version": 2, | |||
} | |||
self.client.post('/api/passwords/', password) | |||
self.client.post("/api/passwords/", password) | |||
self.assertEqual(2, models.Password.objects.first().version) | |||
def test_update_password(self): | |||
password = factories.PasswordFactory(user=self.user) | |||
self.assertNotEqual('facebook.com', password.site) | |||
self.assertNotEqual("facebook.com", password.site) | |||
new_password = { | |||
"site": "facebook.com", | |||
"login": "test@oslab.fr", | |||
@@ -86,19 +86,21 @@ class LoginPasswordsTestCase(APITestCase): | |||
"number": True, | |||
"symbol": True, | |||
"counter": 1, | |||
"length": 12 | |||
"length": 12, | |||
} | |||
request = self.client.put('/api/passwords/%s/' % password.id, new_password) | |||
self.assertEqual(200, request.status_code, request.content.decode('utf-8')) | |||
request = self.client.put("/api/passwords/%s/" % password.id, new_password) | |||
self.assertEqual(200, request.status_code, request.content.decode("utf-8")) | |||
password_updated = models.Password.objects.get(id=password.id) | |||
self.assertEqual('facebook.com', password_updated.site) | |||
self.assertEqual("facebook.com", password_updated.site) | |||
def test_cant_update_other_password(self): | |||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | |||
self.assertEqual('lesspass.com', not_my_password.site) | |||
self.assertEqual("lesspass.com", not_my_password.site) | |||
new_password = { | |||
"site": "facebook", | |||
} | |||
request = self.client.put('/api/passwords/%s/' % not_my_password.id, new_password) | |||
request = self.client.put( | |||
"/api/passwords/%s/" % not_my_password.id, new_password | |||
) | |||
self.assertEqual(404, request.status_code) | |||
self.assertEqual(1, models.Password.objects.all().count()) |
@@ -92,9 +92,15 @@ 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",}, | |||
{ | |||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", | |||
}, | |||
{ | |||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", | |||
}, | |||
{ | |||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", | |||
}, | |||
] | |||
LANGUAGE_CODE = "en-us" | |||
@@ -118,7 +124,11 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "www", "media") | |||
LOGGING = { | |||
"version": 1, | |||
"disable_existing_loggers": False, | |||
"handlers": {"console": {"class": "logging.StreamHandler",}}, | |||
"handlers": { | |||
"console": { | |||
"class": "logging.StreamHandler", | |||
} | |||
}, | |||
"root": { | |||
"handlers": ["console"], | |||
"level": env("DJANGO_LOG_LEVEL", default="DEBUG"), | |||
@@ -128,10 +138,13 @@ LOGGING = { | |||
AUTH_USER_MODEL = "api.LessPassUser" | |||
SIMPLE_JWT = { | |||
'AUTH_HEADER_TYPES': ('Bearer', 'JWT',), | |||
'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=15), | |||
'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=7), | |||
'ROTATE_REFRESH_TOKENS': True, | |||
"AUTH_HEADER_TYPES": ( | |||
"Bearer", | |||
"JWT", | |||
), | |||
"ACCESS_TOKEN_LIFETIME": datetime.timedelta(minutes=15), | |||
"REFRESH_TOKEN_LIFETIME": datetime.timedelta(days=7), | |||
"ROTATE_REFRESH_TOKENS": True, | |||
} | |||
REST_FRAMEWORK = { | |||
@@ -2,6 +2,6 @@ from django.conf.urls import include, url | |||
from django.contrib import admin | |||
urlpatterns = [ | |||
url(r'^api/', include('api.urls')), | |||
url(r'^admin/', admin.site.urls), | |||
url(r"^api/", include("api.urls")), | |||
url(r"^admin/", admin.site.urls), | |||
] |