Resolves the following issue, which occurs with force_otp enabled
and OAuth authentication sources:
File "/srv/powerdnsadmin/powerdnsadmin/models/user.py", line 481, in update_profile
"utf-8") if self.plain_text_password else user.password
AttributeError: 'User' object has no attribute 'plain_text_password'
Starting with the very first commit, the update was always done with
two api calls: one for DELETE and one for REPLACE. It is however
perfectly valid and save to do both at once, which makes it atomic, so
no need for the rollback. Plus it only updates the serial once.
There is no point in sending the full RRset data when deleting it, the
key attributes to identify it are enough. This also make the behaviour
consistent with the api docs [0] where it says "MUST NOT be included
when changetype is set to DELETE."
[0] https://doc.powerdns.com/authoritative/http-api/zone.html#rrset
When enabled, forbids the creation of a domain if it exists as a record in one of its parent domains (administrators and operators are not limited though).
As vermin [0] confirms, the codebase has long moved beyond supporting
python v2 (which is not a bad thing). This removes the last explicit py2
piece of code.
And in case anyone wonders, vermin currently reports the minium version
to be v3.6.
[0] https://pypi.org/project/vermin/
* Previously having characters like "ü" in the SOA wouldnt allow to push
updates to the domain
* Also use the new method to_idna to support characters like "ß"
If the 'otp_force' and 'otp_field_enabled' basic settings are both enabled, automatically enable 2FA for the user after login or signup, if needed, by setting a new OTP secret. Redirect the user to a welcome page for scanning the QR code.
Also show the secret key in ASCII form on the user profile page for easier copying into other applications.
The order of account names returned by User.get_accounts() affects the
order account names are displyed in on /domain/add if the current user
neither has the Administrator role nor the Operator role and the
`allow_user_create_domain` setting is enabled at the same time.
If the current user does have the Administrator or Operator role,
routes.domain.add() already returns accounts ordered by name, so this
change makes it consistent.
The implementation of `random.choice()` uses the Mersenne Twister, the
output of which is predictable by observing previous output, and is as
such unsuitable for security-sensitive applications. A cryptographically
secure pseudorandom number generator - which the `secrets` module relies
on - should be used instead in those instances.