defl/defl/otp_.py
2024-09-11 11:14:03 -04:00

42 lines
1.2 KiB
Python

#!/usr/bin/env python
import base64
import hmac
import re
import struct
import sys
import time
from dataclasses import dataclass
import defl
from defl import cl
from defl import log
from dataclasses import dataclass, field
@dataclass(slots=True, kw_only=True, frozen=False)
class OTP:
cert: str = field(kw_only=False, repr=True)
def __post_init__(_):
_.cert = re.compile(r'\s', flags=re.I).sub(r'', _.cert)
assert re.compile(r'^[0-9A-Za-z]+$', flags=re.I).search(_.cert)
@staticmethod
def _hotp(key, counter, digits=6, digest='sha1'):
key = base64.b32decode(key.upper() + '=' * ((8 - len(key)) % 8))
counter = struct.pack('>Q', counter)
mac = hmac.new(key, counter, digest).digest()
offset = mac[-1] & 0x0f
binary = struct.unpack('>L', mac[offset:offset + 4])[0] & 0x7fffffff
return str(binary)[-digits:].rjust(digits, '0')
@staticmethod
def _totp(key, time_step=30, digits=6, digest='sha1'):
return OTP._hotp(key, int(time.time() / time_step), digits, digest)
def generate(_):
return OTP._totp(_.cert)
if __name__ == '__main__':
res = OTP(cert=sys.argv[1])
log.info(res.generate())