Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
peterthomassen committed Nov 23, 2023
1 parent 6e4bb6e commit ee22229
Showing 1 changed file with 31 additions and 20 deletions.
51 changes: 31 additions & 20 deletions api/desecapi/models/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,20 @@ def generate_key(self):
def make_hash(plain):
return make_password(plain, salt="static", hasher="pbkdf2_sha256_iter1")

def get_policy(self, *, domain=None):
order_by = F("domain").asc(
nulls_last=True
) # default Postgres sorting, but: explicit is better than implicit
def get_policy(self, *, domain=None, subname=None, type=None):
order_by = [
F(field).asc(
nulls_last=True # default Postgres sorting, but: explicit is better than implicit
)
for field in ["domain", "subname", "type"]
]
return (
self.tokendomainpolicy_set.filter(Q(domain=domain) | Q(domain__isnull=True))
.order_by(order_by)
self.tokendomainpolicy_set.filter(
Q(domain=domain) | Q(domain__isnull=True),
Q(subname=subname) | Q(subname__isnull=True),
Q(type=domain) | Q(type__isnull=True),
)
.order_by(*order_by)
.first()
)

Expand All @@ -104,8 +111,8 @@ def delete(self):
# This is needed because Model.delete() emulates cascade delete via django.db.models.deletion.Collector.delete()
# which deletes related objects in pk order. However, the default policy has to be deleted last.
# Perhaps this will change with https://code.djangoproject.com/ticket/21961
self.tokendomainpolicy_set.filter(domain__isnull=False).delete()
self.tokendomainpolicy_set.filter(domain__isnull=True).delete()
self.tokendomainpolicy_set.exclude(domain__isnull=True, subname__isnull=True, type__isnull=True).delete()
self.tokendomainpolicy_set.filter(domain__isnull=True, subname__isnull=True, type__isnull=True).delete()
return super().delete()


Expand All @@ -131,7 +138,7 @@ def delete(self):
name="default_policy_on_update",
operation=pgtrigger.Update,
when=pgtrigger.Before,
condition=pgtrigger.Q(old__domain__isnull=True, new__domain__isnull=False),
condition=pgtrigger.Q(old__domain__isnull=True, new__domain__isnull=False), # TODO or subname or type
),
# Ideally, a deferred trigger (https://github.com/Opus10/django-pgtrigger/issues/14). Available in 3.4.0.
pgtrigger.Trigger(
Expand Down Expand Up @@ -175,29 +182,33 @@ class Meta:
),
]

@property
def has_default_policy_settings(self):
return self.domain is None and self.subname is None and self.type is None

def clean(self):
default_policy = self.token.get_policy(domain=None)
if not self._state.adding: # update
# Can't change policy's default status ("domain NULLness") to maintain policy precedence
if (self.domain is None) != (self.pk == default_policy.pk):
default_policy = self.token.get_policy()
if self._state.adding: # create
# Can't violate policy precedence (default policy has to be first)
if (default_policy is None) and not self.has_default_policy_settings:
raise ValidationError(
{
"domain": "Policy precedence: Cannot disable default policy when others exist."
"domain": "Policy precedence: The first policy must be the default policy."
}
)
else: # create
# Can't violate policy precedence (default policy has to be first)
if (self.domain is not None) and (default_policy is None):
else: # update
# Can't change policy's default status ("domain NULLness") to maintain policy precedence
if self.has_default_policy_settings != (self.pk == default_policy.pk):
raise ValidationError(
{
"domain": "Policy precedence: The first policy must be the default policy."
"domain": "Policy precedence: Cannot disable default policy when others exist."
}
)

def delete(self, *args, **kwargs):
# Can't delete default policy when others exist
if (self.domain is None) and self.token.tokendomainpolicy_set.exclude(
domain__isnull=True
if self.has_default_policy_settings and self.token.tokendomainpolicy_set.exclude(
pk=self.pk
).exists():
raise ValidationError(
{
Expand Down

0 comments on commit ee22229

Please sign in to comment.