Coverage for gws-app/gws/plugin/auth_mfa/totp/__init__.py: 0%
21 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""Multi-factor authentication with time-based one-time passwords.
3The adapter checks TOTP codes generated by authenticator apps. The secret is
4taken from the ``mfaSecret`` attribute of the user; users without it cannot
5start a transaction. The client sends the code as ``{"code": ...}``.
6``key_uri`` creates a key URI for a secret, which can be shown as a QR code to
7set up the app.
9Example::
11 auth.mfa+ {
12 type "totp"
13 uid "AUTH_MFA_TOTP"
14 }
15"""
17import gws
18import gws.base.auth
19import gws.lib.net
20import gws.lib.otp
23@gws.ext.config.authMultiFactorAdapter('totp')
24class Config(gws.base.auth.mfa.Config):
25 """Multi-factor authentication with time-based one-time passwords."""
27 pass
30@gws.ext.object.authMultiFactorAdapter('totp')
31class Object(gws.base.auth.mfa.Object):
32 """TOTP multi-factor adapter."""
34 def start(self, user):
35 if not user.mfaSecret:
36 gws.log.warning(f'totp: cannot start, {user.uid=}: no secret')
37 return
39 mfa = super().start(user)
40 mfa.secret = user.mfaSecret
42 return mfa
44 def verify(self, mfa, payload):
45 ok = self.check_totp(mfa, payload.get('code'))
46 return self.verify_attempt(mfa, ok)
48 def key_uri(self, secret, issuer_name, account_name):
49 return gws.lib.otp.totp_key_uri(secret, issuer_name, account_name, self.otpOptions)