Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

23
class/pyotp/__init__.py Normal file
View File

@@ -0,0 +1,23 @@
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from pyotp.hotp import HOTP # noqa
from pyotp.otp import OTP # noqa
from pyotp.totp import TOTP # noqa
from . import utils # noqa
def random_base32(length=16, random=None,
chars=list('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')):
# Use secrets module if available (Python version >= 3.6) per PEP 506
try:
import secrets
random = secrets.SystemRandom()
except ImportError:
import random as _random
random = _random.SystemRandom()
return ''.join(
random.choice(chars)
for _ in range(length)
)

10
class/pyotp/compat.py Normal file
View File

@@ -0,0 +1,10 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import sys
USING_PYTHON2 = True if sys.version_info < (3, 0) else False
if USING_PYTHON2:
str = unicode # noqa
else:
str = str

58
class/pyotp/hotp.py Normal file
View File

@@ -0,0 +1,58 @@
from __future__ import absolute_import, division, print_function, unicode_literals
from . import utils
from .otp import OTP
from .compat import str
class HOTP(OTP):
"""
Handler for HMAC-based OTP counters.
"""
def at(self, count):
"""
Generates the OTP for the given count.
:param count: the OTP HMAC counter
:type count: int
:returns: OTP
:rtype: str
"""
return self.generate_otp(count)
def verify(self, otp, counter):
"""
Verifies the OTP passed in against the current counter OTP.
:param otp: the OTP to check against
:type otp: str
:param count: the OTP HMAC counter
:type count: int
"""
return utils.strings_equal(str(otp), str(self.at(counter)))
def provisioning_uri(self, name, initial_count=0, issuer_name=None):
"""
Returns the provisioning URI for the OTP. This can then be
encoded in a QR Code and used to provision an OTP app like
Google Authenticator.
See also:
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
:param name: name of the user account
:type name: str
:param initial_count: starting HMAC counter value, defaults to 0
:type initial_count: int
:param issuer_name: the name of the OTP issuer; this will be the
organization title of the OTP entry in Authenticator
:returns: provisioning URI
:rtype: str
"""
return utils.build_uri(
self.secret,
name,
initial_count=initial_count,
issuer_name=issuer_name,
algorithm=self.digest().name,
digits=self.digits
)

66
class/pyotp/otp.py Normal file
View File

@@ -0,0 +1,66 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import base64
import hashlib
import hmac
from .compat import str
class OTP(object):
"""
Base class for OTP handlers.
"""
def __init__(self, s, digits=6, digest=hashlib.sha1):
"""
:param s: secret in base32 format
:type s: str
:param digits: number of integers in the OTP. Some apps expect this to be 6 digits, others support more.
:type digits: int
:param digest: digest function to use in the HMAC (expected to be sha1)
:type digest: callable
"""
self.digits = digits
self.digest = digest
self.secret = s
def generate_otp(self, input):
"""
:param input: the HMAC counter value to use as the OTP input.
Usually either the counter, or the computed integer based on the Unix timestamp
:type input: int
"""
if input < 0:
raise ValueError('input must be positive integer')
hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
hmac_hash = bytearray(hasher.digest())
offset = hmac_hash[-1] & 0xf
code = ((hmac_hash[offset] & 0x7f) << 24 |
(hmac_hash[offset + 1] & 0xff) << 16 |
(hmac_hash[offset + 2] & 0xff) << 8 |
(hmac_hash[offset + 3] & 0xff))
str_code = str(code % 10 ** self.digits)
while len(str_code) < self.digits:
str_code = '0' + str_code
return str_code
def byte_secret(self):
missing_padding = len(self.secret) % 8
if missing_padding != 0:
self.secret += '=' * (8 - missing_padding)
return base64.b32decode(self.secret, casefold=True)
@staticmethod
def int_to_bytestring(i, padding=8):
"""
Turns an integer to the OATH specified
bytestring, which is fed to the HMAC
along with the secret
"""
result = bytearray()
while i != 0:
result.append(i & 0xFF)
i >>= 8
# It's necessary to convert the final result from bytearray to bytes
# because the hmac functions in python 2.6 and 3.3 don't work with
# bytearray
return bytes(bytearray(reversed(result)).rjust(padding, b'\0'))

92
class/pyotp/totp.py Normal file
View File

@@ -0,0 +1,92 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import datetime
import time
from . import utils
from .otp import OTP
from .compat import str
class TOTP(OTP):
"""
Handler for time-based OTP counters.
"""
def __init__(self, *args, **kwargs):
"""
:param interval: the time interval in seconds
for OTP. This defaults to 30.
:type interval: int
"""
self.interval = kwargs.pop('interval', 30)
super(TOTP, self).__init__(*args, **kwargs)
def at(self, for_time, counter_offset=0):
"""
Accepts either a Unix timestamp integer or a datetime object.
:param for_time: the time to generate an OTP for
:type for_time: int or datetime
:param counter_offset: the amount of ticks to add to the time counter
:returns: OTP value
:rtype: str
"""
if not isinstance(for_time, datetime.datetime):
for_time = datetime.datetime.fromtimestamp(int(for_time))
return self.generate_otp(self.timecode(for_time) + counter_offset)
def now(self):
"""
Generate the current time OTP
:returns: OTP value
:rtype: str
"""
return self.generate_otp(self.timecode(datetime.datetime.now()))
def verify(self, otp, for_time=None, valid_window=0):
"""
Verifies the OTP passed in against the current time OTP.
:param otp: the OTP to check against
:type otp: str
:param for_time: Time to check OTP at (defaults to now)
:type for_time: int or datetime
:param valid_window: extends the validity to this many counter ticks before and after the current one
:type valid_window: int
:returns: True if verification succeeded, False otherwise
:rtype: bool
"""
if for_time is None:
for_time = datetime.datetime.now()
if valid_window:
for i in range(-valid_window, valid_window + 1):
if utils.strings_equal(str(otp), str(self.at(for_time, i))):
return True
return False
return utils.strings_equal(str(otp), str(self.at(for_time)))
def provisioning_uri(self, name, issuer_name=None):
"""
Returns the provisioning URI for the OTP. This can then be
encoded in a QR Code and used to provision an OTP app like
Google Authenticator.
See also:
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
:param name: name of the user account
:type name: str
:param issuer_name: the name of the OTP issuer; this will be the
organization title of the OTP entry in Authenticator
:returns: provisioning URI
:rtype: str
"""
return utils.build_uri(self.secret, name, issuer_name=issuer_name,
algorithm=self.digest().name,
digits=self.digits, period=self.interval)
def timecode(self, for_time):
i = time.mktime(for_time.timetuple())
return int(i / self.interval)

109
class/pyotp/utils.py Normal file
View File

@@ -0,0 +1,109 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import unicodedata
try:
from itertools import izip_longest
except ImportError:
from itertools import zip_longest as izip_longest
try:
from urllib.parse import quote, urlencode
except ImportError:
from urllib import quote, urlencode
def build_uri(secret, name, initial_count=None, issuer_name=None,
algorithm=None, digits=None, period=None):
"""
Returns the provisioning URI for the OTP; works for either TOTP or HOTP.
This can then be encoded in a QR Code and used to provision the Google
Authenticator app.
For module-internal use.
See also:
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
:param secret: the hotp/totp secret used to generate the URI
:type secret: str
:param name: name of the account
:type name: str
:param initial_count: starting counter value, defaults to None.
If none, the OTP type will be assumed as TOTP.
:type initial_count: int
:param issuer_name: the name of the OTP issuer; this will be the
organization title of the OTP entry in Authenticator
:type issuer_name: str
:param algorithm: the algorithm used in the OTP generation.
:type algorithm: str
:param digits: the length of the OTP generated code.
:type digits: int
:param period: the number of seconds the OTP generator is set to
expire every code.
:type period: int
:returns: provisioning uri
:rtype: str
"""
# initial_count may be 0 as a valid param
is_initial_count_present = (initial_count is not None)
# Handling values different from defaults
is_algorithm_set = (algorithm is not None and algorithm != 'sha1')
is_digits_set = (digits is not None and digits != 6)
is_period_set = (period is not None and period != 30)
otp_type = 'hotp' if is_initial_count_present else 'totp'
base_uri = 'otpauth://{0}/{1}?{2}'
url_args = {'secret': secret}
label = quote(name)
if issuer_name is not None:
label = quote(issuer_name) + ':' + label
url_args['issuer'] = issuer_name
if is_initial_count_present:
url_args['counter'] = initial_count
if is_algorithm_set:
url_args['algorithm'] = algorithm.upper()
if is_digits_set:
url_args['digits'] = digits
if is_period_set:
url_args['period'] = period
uri = base_uri.format(otp_type, label, urlencode(url_args).replace("+", "%20"))
return uri
def _compare_digest(s1, s2):
differences = 0
for c1, c2 in izip_longest(s1, s2):
if c1 is None or c2 is None:
differences = 1
continue
differences |= ord(c1) ^ ord(c2)
return differences == 0
try:
# Python 3.3+ and 2.7.7+ include a timing-attack-resistant
# comparison function, which is probably more reliable than ours.
# Use it if available.
from hmac import compare_digest
except ImportError:
compare_digest = _compare_digest
def strings_equal(s1, s2):
"""
Timing-attack resistant string comparison.
Normal comparison using == will short-circuit on the first mismatching
character. This avoids that by scanning the whole string, though we
still reveal to a timing attack whether the strings are the same
length.
"""
s1 = unicodedata.normalize('NFKC', s1)
s2 = unicodedata.normalize('NFKC', s2)
return compare_digest(s1.encode("utf-8"), s2.encode("utf-8"))