@@ -10,12 +10,14 @@ from django.db.models import Count | |||||
class UserCreationForm(forms.ModelForm): | 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: | class Meta: | ||||
model = LessPassUser | model = LessPassUser | ||||
fields = ('email',) | |||||
fields = ("email",) | |||||
def clean_password2(self): | def clean_password2(self): | ||||
password1 = self.cleaned_data.get("password1") | password1 = self.cleaned_data.get("password1") | ||||
@@ -37,7 +39,7 @@ class UserChangeForm(forms.ModelForm): | |||||
class Meta: | class Meta: | ||||
model = LessPassUser | model = LessPassUser | ||||
fields = ('email', 'password', 'is_active', 'is_admin') | |||||
fields = ("email", "password", "is_active", "is_admin") | |||||
def clean_password(self): | def clean_password(self): | ||||
return self.initial["password"] | return self.initial["password"] | ||||
@@ -47,36 +49,36 @@ class LessPassUserAdmin(BaseUserAdmin): | |||||
form = UserChangeForm | form = UserChangeForm | ||||
add_form = UserCreationForm | 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 = ( | fieldsets = ( | ||||
(None, {'fields': ('email', 'password')}), | |||||
('Permissions', {'fields': ('is_admin',)}), | |||||
(None, {"fields": ("email", "password")}), | |||||
("Permissions", {"fields": ("is_admin",)}), | |||||
) | ) | ||||
add_fieldsets = ( | 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 = () | filter_horizontal = () | ||||
def get_queryset(self, request): | 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): | def column_passwords_count(self, instance): | ||||
return instance.passwords_count | 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): | 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) | admin.site.register(models.Password, PasswordAdmin) | ||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig | |||||
class ApiConfig(AppConfig): | class ApiConfig(AppConfig): | ||||
name = 'api' | |||||
name = "api" |
@@ -12,62 +12,107 @@ class Migration(migrations.Migration): | |||||
initial = True | initial = True | ||||
dependencies = [ | |||||
] | |||||
dependencies = [] | |||||
operations = [ | operations = [ | ||||
migrations.CreateModel( | migrations.CreateModel( | ||||
name='LessPassUser', | |||||
name="LessPassUser", | |||||
fields=[ | 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={ | options={ | ||||
'verbose_name_plural': 'Users', | |||||
"verbose_name_plural": "Users", | |||||
}, | }, | ||||
), | ), | ||||
migrations.CreateModel( | migrations.CreateModel( | ||||
name='Entry', | |||||
name="Entry", | |||||
fields=[ | 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={ | options={ | ||||
'verbose_name_plural': 'Entries', | |||||
"verbose_name_plural": "Entries", | |||||
}, | }, | ||||
), | ), | ||||
migrations.CreateModel( | migrations.CreateModel( | ||||
name='PasswordInfo', | |||||
name="PasswordInfo", | |||||
fields=[ | 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={ | options={ | ||||
'verbose_name_plural': 'Password info', | |||||
"verbose_name_plural": "Password info", | |||||
}, | }, | ||||
), | ), | ||||
migrations.AddField( | 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( | 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): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0001_initial'), | |||||
("api", "0001_initial"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.CreateModel( | migrations.CreateModel( | ||||
name='Password', | |||||
name="Password", | |||||
fields=[ | 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={ | options={ | ||||
'abstract': False, | |||||
"abstract": False, | |||||
}, | }, | ||||
), | ), | ||||
] | ] |
@@ -11,14 +11,23 @@ from api import models | |||||
def create_password_with(entry): | def create_password_with(entry): | ||||
settings = json.dumps(entry.password.settings) | 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) | 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): | def mv_entries_to_password(apps, schema_editor): | ||||
@@ -29,7 +38,7 @@ def mv_entries_to_password(apps, schema_editor): | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0002_password'), | |||||
("api", "0002_password"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
@@ -8,22 +8,22 @@ from django.db import migrations | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0003_mv_entries_to_password'), | |||||
("api", "0003_mv_entries_to_password"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.RemoveField( | migrations.RemoveField( | ||||
model_name='entry', | |||||
name='password', | |||||
model_name="entry", | |||||
name="password", | |||||
), | ), | ||||
migrations.RemoveField( | migrations.RemoveField( | ||||
model_name='entry', | |||||
name='user', | |||||
model_name="entry", | |||||
name="user", | |||||
), | ), | ||||
migrations.DeleteModel( | migrations.DeleteModel( | ||||
name='Entry', | |||||
name="Entry", | |||||
), | ), | ||||
migrations.DeleteModel( | migrations.DeleteModel( | ||||
name='PasswordInfo', | |||||
name="PasswordInfo", | |||||
), | ), | ||||
] | ] |
@@ -8,13 +8,13 @@ from django.db import migrations, models | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0004_remove_entries_password_info_models'), | |||||
("api", "0004_remove_entries_password_info_models"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.AddField( | migrations.AddField( | ||||
model_name='password', | |||||
name='version', | |||||
model_name="password", | |||||
name="version", | |||||
field=models.IntegerField(default=1), | field=models.IntegerField(default=1), | ||||
), | ), | ||||
] | ] |
@@ -8,18 +8,18 @@ from django.db import migrations, models | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0005_password_version'), | |||||
("api", "0005_password_version"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.AlterField( | migrations.AlterField( | ||||
model_name='password', | |||||
name='length', | |||||
model_name="password", | |||||
name="length", | |||||
field=models.IntegerField(default=16), | field=models.IntegerField(default=16), | ||||
), | ), | ||||
migrations.AlterField( | migrations.AlterField( | ||||
model_name='password', | |||||
name='version', | |||||
model_name="password", | |||||
name="version", | |||||
field=models.IntegerField(default=2), | field=models.IntegerField(default=2), | ||||
), | ), | ||||
] | ] |
@@ -6,13 +6,13 @@ from django.db import migrations, models | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0006_change_default_password_profile'), | |||||
("api", "0006_change_default_password_profile"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.AddField( | migrations.AddField( | ||||
model_name='lesspassuser', | |||||
name='key', | |||||
model_name="lesspassuser", | |||||
name="key", | |||||
field=models.TextField(null=True), | field=models.TextField(null=True), | ||||
), | ), | ||||
] | ] |
@@ -9,21 +9,42 @@ import uuid | |||||
class Migration(migrations.Migration): | class Migration(migrations.Migration): | ||||
dependencies = [ | dependencies = [ | ||||
('api', '0007_lesspassuser_key'), | |||||
("api", "0007_lesspassuser_key"), | |||||
] | ] | ||||
operations = [ | operations = [ | ||||
migrations.CreateModel( | migrations.CreateModel( | ||||
name='EncryptedPasswordProfile', | |||||
name="EncryptedPasswordProfile", | |||||
fields=[ | 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={ | options={ | ||||
'abstract': False, | |||||
"abstract": False, | |||||
}, | }, | ||||
), | ), | ||||
] | ] |
@@ -40,7 +40,9 @@ class EncryptedPasswordProfileSerializer(serializers.ModelSerializer): | |||||
def create(self, validated_data): | def create(self, validated_data): | ||||
user = self.context["request"].user | 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): | class BackwardCompatibleTokenObtainPairSerializer(TokenObtainPairSerializer): | ||||
@@ -60,11 +60,12 @@ class OldLoginTestCase(APITestCase): | |||||
"password": "correct horse battery staple", | "password": "correct horse battery staple", | ||||
} | } | ||||
request = self.client.post("/api/tokens/auth/", data) | 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) | request = self.client.get("/api/passwords/", **headers) | ||||
self.assertEqual(request.status_code, 200) | 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): | def test_nrt_get_passwords_with_bearer(self): | ||||
user = factories.UserFactory( | user = factories.UserFactory( | ||||
@@ -76,7 +77,9 @@ class OldLoginTestCase(APITestCase): | |||||
"password": "correct horse battery staple", | "password": "correct horse battery staple", | ||||
} | } | ||||
request = self.client.post("/api/auth/jwt/create/", data) | 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) | request = self.client.get("/api/passwords/", **headers) | ||||
self.assertEqual(request.status_code, 200) | 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): | class LogoutPasswordsTestCase(APITestCase): | ||||
def test_get_passwords_401(self): | def test_get_passwords_401(self): | ||||
response = self.client.get('/api/passwords/') | |||||
response = self.client.get("/api/passwords/") | |||||
self.assertEqual(401, response.status_code) | self.assertEqual(401, response.status_code) | ||||
@@ -17,31 +17,31 @@ class LoginPasswordsTestCase(APITestCase): | |||||
self.client.force_authenticate(user=self.user) | self.client.force_authenticate(user=self.user) | ||||
def test_get_empty_passwords(self): | 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): | def test_retrieve_its_own_passwords(self): | ||||
password = factories.PasswordFactory(user=self.user) | 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): | def test_cant_retrieve_other_passwords(self): | ||||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | 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) | self.assertEqual(404, request.status_code) | ||||
def test_delete_its_own_passwords(self): | def test_delete_its_own_passwords(self): | ||||
password = factories.PasswordFactory(user=self.user) | password = factories.PasswordFactory(user=self.user) | ||||
self.assertEqual(1, models.Password.objects.all().count()) | 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(204, request.status_code) | ||||
self.assertEqual(0, models.Password.objects.all().count()) | self.assertEqual(0, models.Password.objects.all().count()) | ||||
def test_cant_delete_other_password(self): | def test_cant_delete_other_password(self): | ||||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | ||||
self.assertEqual(1, models.Password.objects.all().count()) | 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(404, request.status_code) | ||||
self.assertEqual(1, models.Password.objects.all().count()) | self.assertEqual(1, models.Password.objects.all().count()) | ||||
@@ -54,10 +54,10 @@ class LoginPasswordsTestCase(APITestCase): | |||||
"number": True, | "number": True, | ||||
"symbol": True, | "symbol": True, | ||||
"counter": 1, | "counter": 1, | ||||
"length": 12 | |||||
"length": 12, | |||||
} | } | ||||
self.assertEqual(0, models.Password.objects.count()) | 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()) | self.assertEqual(1, models.Password.objects.count()) | ||||
def test_create_password_v2(self): | def test_create_password_v2(self): | ||||
@@ -70,14 +70,14 @@ class LoginPasswordsTestCase(APITestCase): | |||||
"symbol": True, | "symbol": True, | ||||
"counter": 1, | "counter": 1, | ||||
"length": 12, | "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) | self.assertEqual(2, models.Password.objects.first().version) | ||||
def test_update_password(self): | def test_update_password(self): | ||||
password = factories.PasswordFactory(user=self.user) | password = factories.PasswordFactory(user=self.user) | ||||
self.assertNotEqual('facebook.com', password.site) | |||||
self.assertNotEqual("facebook.com", password.site) | |||||
new_password = { | new_password = { | ||||
"site": "facebook.com", | "site": "facebook.com", | ||||
"login": "test@oslab.fr", | "login": "test@oslab.fr", | ||||
@@ -86,19 +86,21 @@ class LoginPasswordsTestCase(APITestCase): | |||||
"number": True, | "number": True, | ||||
"symbol": True, | "symbol": True, | ||||
"counter": 1, | "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) | 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): | def test_cant_update_other_password(self): | ||||
not_my_password = factories.PasswordFactory(user=factories.UserFactory()) | 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 = { | new_password = { | ||||
"site": "facebook", | "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(404, request.status_code) | ||||
self.assertEqual(1, models.Password.objects.all().count()) | 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.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" | LANGUAGE_CODE = "en-us" | ||||
@@ -118,7 +124,11 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "www", "media") | |||||
LOGGING = { | LOGGING = { | ||||
"version": 1, | "version": 1, | ||||
"disable_existing_loggers": False, | "disable_existing_loggers": False, | ||||
"handlers": {"console": {"class": "logging.StreamHandler",}}, | |||||
"handlers": { | |||||
"console": { | |||||
"class": "logging.StreamHandler", | |||||
} | |||||
}, | |||||
"root": { | "root": { | ||||
"handlers": ["console"], | "handlers": ["console"], | ||||
"level": env("DJANGO_LOG_LEVEL", default="DEBUG"), | "level": env("DJANGO_LOG_LEVEL", default="DEBUG"), | ||||
@@ -128,10 +138,13 @@ LOGGING = { | |||||
AUTH_USER_MODEL = "api.LessPassUser" | AUTH_USER_MODEL = "api.LessPassUser" | ||||
SIMPLE_JWT = { | 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 = { | REST_FRAMEWORK = { | ||||
@@ -2,6 +2,6 @@ from django.conf.urls import include, url | |||||
from django.contrib import admin | from django.contrib import admin | ||||
urlpatterns = [ | 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), | |||||
] | ] |