diff --git a/account/migrations/0001_initial.py b/account/migrations/0001_initial.py index b57be4b6..a028551e 100644 --- a/account/migrations/0001_initial.py +++ b/account/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-09-25 05:30 +# Generated by Django 1.9.12 on 2017-01-23 07:59 from __future__ import unicode_literals import account.models @@ -24,19 +24,17 @@ class Migration(migrations.Migration): ('password', models.CharField(max_length=128, verbose_name='password')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('username', models.CharField(max_length=30, unique=True)), - ('real_name', models.CharField(blank=True, max_length=30, null=True)), - ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('real_name', models.CharField(max_length=30, null=True)), + ('email', models.EmailField(max_length=254, null=True)), ('create_time', models.DateTimeField(auto_now_add=True, null=True)), - ('admin_type', models.IntegerField(default=0)), - ('admin_extra_permission', jsonfield.fields.JSONField(default=[])), - ('problems_status', jsonfield.fields.JSONField(default={})), - ('reset_password_token', models.CharField(blank=True, max_length=40, null=True)), - ('reset_password_token_create_time', models.DateTimeField(blank=True, null=True)), - ('auth_token', models.CharField(blank=True, max_length=40, null=True)), + ('admin_type', models.CharField(default='regular_user', max_length=24)), + ('reset_password_token', models.CharField(max_length=40, null=True)), + ('reset_password_token_expire_time', models.DateTimeField(null=True)), + ('auth_token', models.CharField(max_length=40, null=True)), ('two_factor_auth', models.BooleanField(default=False)), - ('tfa_token', models.CharField(blank=True, max_length=40, null=True)), + ('tfa_token', models.CharField(max_length=40, null=True)), ('open_api', models.BooleanField(default=False)), - ('open_api_appkey', models.CharField(blank=True, max_length=35, null=True)), + ('open_api_appkey', models.CharField(max_length=35, null=True)), ('is_disabled', models.BooleanField(default=False)), ], options={ @@ -50,17 +48,18 @@ class Migration(migrations.Migration): name='UserProfile', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('problems_status', jsonfield.fields.JSONField(default={})), ('avatar', models.CharField(default=account.models._random_avatar, max_length=50)), ('blog', models.URLField(blank=True, null=True)), ('mood', models.CharField(blank=True, max_length=200, null=True)), - ('hduoj_username', models.CharField(blank=True, max_length=30, null=True)), - ('bestcoder_username', models.CharField(blank=True, max_length=30, null=True)), - ('codeforces_username', models.CharField(blank=True, max_length=30, null=True)), ('accepted_problem_number', models.IntegerField(default=0)), ('submission_number', models.IntegerField(default=0)), ('phone_number', models.CharField(blank=True, max_length=15, null=True)), ('school', models.CharField(blank=True, max_length=200, null=True)), + ('major', models.CharField(blank=True, max_length=200, null=True)), ('student_id', models.CharField(blank=True, max_length=15, null=True)), + ('time_zone', models.CharField(blank=True, max_length=32, null=True)), + ('language', models.CharField(blank=True, max_length=32, null=True)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ diff --git a/account/migrations/0002_auto_20160925_1337.py b/account/migrations/0002_auto_20160925_1337.py deleted file mode 100644 index 84a6ea3b..00000000 --- a/account/migrations/0002_auto_20160925_1337.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-09-25 05:37 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='user', - name='real_name', - ), - migrations.RemoveField( - model_name='userprofile', - name='bestcoder_username', - ), - migrations.RemoveField( - model_name='userprofile', - name='codeforces_username', - ), - migrations.RemoveField( - model_name='userprofile', - name='hduoj_username', - ), - migrations.AddField( - model_name='userprofile', - name='real_name', - field=models.CharField(blank=True, max_length=30, null=True), - ), - ] diff --git a/account/migrations/0003_auto_20160925_1402.py b/account/migrations/0003_auto_20160925_1402.py deleted file mode 100644 index a14d553a..00000000 --- a/account/migrations/0003_auto_20160925_1402.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-09-25 06:02 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0002_auto_20160925_1337'), - ] - - operations = [ - migrations.RemoveField( - model_name='userprofile', - name='real_name', - ), - migrations.AddField( - model_name='user', - name='real_name', - field=models.CharField(blank=True, max_length=30, null=True), - ), - ] diff --git a/account/migrations/0004_auto_20160925_1649.py b/account/migrations/0004_auto_20160925_1649.py deleted file mode 100644 index 3b54ecfc..00000000 --- a/account/migrations/0004_auto_20160925_1649.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-09-25 08:49 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0003_auto_20160925_1402'), - ] - - operations = [ - migrations.AddField( - model_name='userprofile', - name='language', - field=models.CharField(blank=True, max_length=32, null=True), - ), - migrations.AddField( - model_name='userprofile', - name='major', - field=models.CharField(blank=True, max_length=200, null=True), - ), - migrations.AddField( - model_name='userprofile', - name='time_zone', - field=models.CharField(blank=True, max_length=32, null=True), - ), - migrations.AlterField( - model_name='user', - name='auth_token', - field=models.CharField(max_length=40, null=True), - ), - migrations.AlterField( - model_name='user', - name='email', - field=models.EmailField(max_length=254, null=True), - ), - migrations.AlterField( - model_name='user', - name='open_api_appkey', - field=models.CharField(max_length=35, null=True), - ), - migrations.AlterField( - model_name='user', - name='real_name', - field=models.CharField(max_length=30, null=True), - ), - migrations.AlterField( - model_name='user', - name='reset_password_token', - field=models.CharField(max_length=40, null=True), - ), - migrations.AlterField( - model_name='user', - name='reset_password_token_create_time', - field=models.DateTimeField(null=True), - ), - migrations.AlterField( - model_name='user', - name='tfa_token', - field=models.CharField(max_length=40, null=True), - ), - ] diff --git a/account/migrations/0005_auto_20161029_2255.py b/account/migrations/0005_auto_20161029_2255.py deleted file mode 100644 index 48457156..00000000 --- a/account/migrations/0005_auto_20161029_2255.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-10-29 14:55 -from __future__ import unicode_literals - -from django.db import migrations, models -import jsonfield.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('account', '0004_auto_20160925_1649'), - ] - - operations = [ - migrations.RenameField( - model_name='user', - old_name='reset_password_token_create_time', - new_name='reset_password_token_expire_time', - ), - migrations.RemoveField( - model_name='user', - name='admin_extra_permission', - ), - migrations.RemoveField( - model_name='user', - name='problems_status', - ), - migrations.AddField( - model_name='userprofile', - name='problems_status', - field=jsonfield.fields.JSONField(default={}), - ), - migrations.AlterField( - model_name='user', - name='admin_type', - field=models.CharField(default='regular_user', max_length=24), - ), - ] diff --git a/account/models.py b/account/models.py index faeab5d2..c7bf5f36 100644 --- a/account/models.py +++ b/account/models.py @@ -39,7 +39,7 @@ class User(AbstractBaseUser): open_api_appkey = models.CharField(max_length=35, null=True) is_disabled = models.BooleanField(default=False) - USERNAME_FIELD = 'username' + USERNAME_FIELD = "username" REQUIRED_FIELDS = [] objects = UserManager() diff --git a/account/views/admin.py b/account/views/admin.py index 471e9732..a5d94891 100644 --- a/account/views/admin.py +++ b/account/views/admin.py @@ -84,12 +84,6 @@ class UserAdminAPI(APIView): user = User.objects.all().order_by("-create_time") - admin_type = request.GET.get("admin_type", None) - if admin_type: - try: - user = user.filter(admin_type__gte=int(admin_type)) - except ValueError: - return self.error(_("Invalid parameter")) keyword = request.GET.get("keyword", None) if keyword: user = user.filter(Q(username__contains=keyword) | diff --git a/account/views/oj.py b/account/views/oj.py index 91dd749a..fb501990 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -2,9 +2,10 @@ from django.contrib import auth from django.core.exceptions import MultipleObjectsReturned from django.utils.translation import ugettext as _ +from otpauth import OtpAuth + from utils.api import APIView, validate_serializer from utils.captcha import Captcha -from utils.otp_auth import OtpAuth from ..decorators import login_required from ..models import User, UserProfile from ..serializers import (UserLoginSerializer, UserRegisterSerializer, diff --git a/announcement/migrations/0001_initial.py b/announcement/migrations/0001_initial.py index 4a09bb95..345a10f6 100644 --- a/announcement/migrations/0001_initial.py +++ b/announcement/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9.5 on 2016-09-25 05:32 +# Generated by Django 1.9.12 on 2017-01-23 07:59 from __future__ import unicode_literals from django.conf import settings diff --git a/conf/migrations/0001_initial.py b/conf/migrations/0001_initial.py index 44c393c4..46c7dc39 100644 --- a/conf/migrations/0001_initial.py +++ b/conf/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9.10 on 2016-11-19 05:18 +# Generated by Django 1.9.12 on 2017-01-23 07:59 from __future__ import unicode_literals from django.db import migrations, models @@ -13,6 +13,35 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='JudgeServer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('hostname', models.CharField(max_length=64)), + ('ip', models.CharField(blank=True, max_length=32, null=True)), + ('judger_version', models.CharField(max_length=24)), + ('cpu_core', models.IntegerField()), + ('memory_usage', models.FloatField()), + ('cpu_usage', models.FloatField()), + ('last_heartbeat', models.DateTimeField()), + ('create_time', models.DateTimeField(auto_now_add=True)), + ('task_number', models.IntegerField(default=0)), + ('service_url', models.CharField(blank=True, max_length=128, null=True)), + ], + options={ + 'db_table': 'judge_server', + }, + ), + migrations.CreateModel( + name='JudgeServerToken', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('token', models.CharField(max_length=32)), + ], + options={ + 'db_table': 'judge_server_token', + }, + ), migrations.CreateModel( name='SMTPConfig', fields=[ @@ -34,7 +63,7 @@ class Migration(migrations.Migration): ('base_url', models.CharField(default='http://127.0.0.1', max_length=128)), ('name', models.CharField(default='Online Judge', max_length=32)), ('name_shortcut', models.CharField(default='oj', max_length=32)), - ('website_footer', models.TextField(default='Online Judge Footer')), + ('footer', models.TextField(default='Online Judge Footer')), ('allow_register', models.BooleanField(default=True)), ('submission_list_show_all', models.BooleanField(default=True)), ], diff --git a/conf/migrations/0002_auto_20161119_1657.py b/conf/migrations/0002_auto_20161119_1657.py deleted file mode 100644 index 0141f309..00000000 --- a/conf/migrations/0002_auto_20161119_1657.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.10 on 2016-11-19 08:57 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('conf', '0001_initial'), - ] - - operations = [ - migrations.RenameField( - model_name='websiteconfig', - old_name='website_footer', - new_name='footer', - ), - ] diff --git a/conf/migrations/0003_judgeserver.py b/conf/migrations/0003_judgeserver.py deleted file mode 100644 index f8bf93e7..00000000 --- a/conf/migrations/0003_judgeserver.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.10 on 2016-11-19 14:27 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('conf', '0002_auto_20161119_1657'), - ] - - operations = [ - migrations.CreateModel( - name='JudgeServer', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('hostname', models.CharField(max_length=64)), - ('ip', models.CharField(max_length=32)), - ('judger_version', models.CharField(max_length=24)), - ('cpu_core', models.IntegerField()), - ('memory_usage', models.FloatField()), - ('cpu_usage', models.FloatField()), - ('last_heartbeat', models.DateTimeField()), - ('create_time', models.DateTimeField(auto_now_add=True)), - ('task_number', models.IntegerField()), - ], - options={ - 'db_table': 'judge_server', - }, - ), - ] diff --git a/conf/migrations/0004_auto_20161120_1834.py b/conf/migrations/0004_auto_20161120_1834.py deleted file mode 100644 index f6d88dad..00000000 --- a/conf/migrations/0004_auto_20161120_1834.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.10 on 2016-11-20 10:34 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('conf', '0003_judgeserver'), - ] - - operations = [ - migrations.AddField( - model_name='judgeserver', - name='service_url', - field=models.CharField(blank=True, max_length=128, null=True), - ), - migrations.AlterField( - model_name='judgeserver', - name='ip', - field=models.CharField(blank=True, max_length=32, null=True), - ), - ] diff --git a/conf/migrations/0005_judgeservertoken.py b/conf/migrations/0005_judgeservertoken.py deleted file mode 100644 index 7c930103..00000000 --- a/conf/migrations/0005_judgeservertoken.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9.10 on 2016-11-20 11:00 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('conf', '0004_auto_20161120_1834'), - ] - - operations = [ - migrations.CreateModel( - name='JudgeServerToken', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('token', models.CharField(max_length=32)), - ], - options={ - 'db_table': 'judge_server_token', - }, - ), - ] diff --git a/conf/models.py b/conf/models.py index 3b09443b..33a6ae06 100644 --- a/conf/models.py +++ b/conf/models.py @@ -1,6 +1,3 @@ -# coding=utf-8 -from __future__ import unicode_literals - from django.db import models diff --git a/conf/views.py b/conf/views.py index 1a4bb11b..746fbfb2 100644 --- a/conf/views.py +++ b/conf/views.py @@ -21,15 +21,15 @@ class SMTPAPI(APIView): return self.success(None) return self.success(SMTPConfigSerializer(smtp).data) - @super_admin_required @validate_serializer(CreateSMTPConfigSerializer) + @super_admin_required def post(self, request): SMTPConfig.objects.all().delete() smtp = SMTPConfig.objects.create(**request.data) return self.success(SMTPConfigSerializer(smtp).data) - @super_admin_required @validate_serializer(EditSMTPConfigSerializer) + @super_admin_required def put(self, request): data = request.data smtp = SMTPConfig.objects.first() diff --git a/contest/migrations/__init__.py b/contest/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/deploy/requirements.txt b/deploy/requirements.txt index 1802f991..39972325 100644 --- a/deploy/requirements.txt +++ b/deploy/requirements.txt @@ -2,3 +2,4 @@ Django<1.10 djangorestframework==3.3.3 pillow jsonfield +otpauth diff --git a/group/migrations/__init__.py b/group/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/problem/migrations/__init__.py b/problem/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/utils/management/commands/initadmin.py b/utils/management/commands/initadmin.py index cfac5d4e..f7adedbe 100644 --- a/utils/management/commands/initadmin.py +++ b/utils/management/commands/initadmin.py @@ -1,4 +1,3 @@ -# coding=utf-8 from django.core.management.base import BaseCommand from account.models import User, UserProfile, AdminType from utils.shortcuts import rand_str @@ -12,9 +11,10 @@ class Command(BaseCommand): self.stdout.write(self.style.WARNING("Super admin user 'root' already exists, " "would you like to reset it's password?\n" "Input yes to confirm: ")) - if raw_input() == "yes": + if input() == "yes": rand_password = rand_str(length=6) - admin.set_password(rand_password) + # admin.set_password(rand_password) + admin.set_password("rootroot") admin.save() self.stdout.write(self.style.SUCCESS("Successfully created super admin user password.\n" "Username: root\nPassword: %s\n" @@ -27,7 +27,9 @@ class Command(BaseCommand): except User.DoesNotExist: user = User.objects.create(username="root", email="root@oj.com", admin_type=AdminType.SUPER_ADMIN) rand_password = rand_str(length=6) - user.set_password(rand_password) + # user.set_password(rand_password) + # for dev + user.set_password("rootroot") user.save() UserProfile.objects.create(user=user) self.stdout.write(self.style.SUCCESS("Successfully created super admin user.\n" diff --git a/utils/otp_auth.py b/utils/otp_auth.py deleted file mode 100644 index 12773c4e..00000000 --- a/utils/otp_auth.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- -""" - otpauth - ~~~~~~~ - - Implements two-step verification of HOTP/TOTP. - - :copyright: (c) 2013 - 2015 by Hsiaoming Yang. - :license: BSD, see LICENSE for more details. -""" -import sys -import time -import hmac -import base64 -import struct -import hashlib -import warnings - - -if sys.version_info[0] == 3: - PY2 = False - string_type = str -else: - PY2 = True - string_type = unicode - range = xrange - - -__author__ = 'Hsiaoming Yang ' -__homepage__ = 'https://github.com/lepture/otpauth' -__version__ = '1.0.1' - - -__all__ = ['OtpAuth', 'HOTP', 'TOTP', 'generate_hotp', 'generate_totp'] - - -HOTP = 'hotp' -TOTP = 'totp' - - -class OtpAuth(object): - """One Time Password Authentication. - - :param secret: A secret token for the authentication. - """ - - def __init__(self, secret): - self.secret = secret - - def hotp(self, counter=4): - """Generate a HOTP code. - - :param counter: HOTP is a counter based algorithm. - """ - return generate_hotp(self.secret, counter) - - def totp(self, period=30, timestamp=None): - """Generate a TOTP code. - - A TOTP code is an extension of HOTP algorithm. - - :param period: A period that a TOTP code is valid in seconds - :param timestamp: Create TOTP at this given timestamp - """ - return generate_totp(self.secret, period, timestamp) - - def valid_hotp(self, code, last=0, trials=100): - """Valid a HOTP code. - - :param code: A number that is less than 6 characters. - :param last: Guess HOTP code from last + 1 range. - :param trials: Guest HOTP code end at last + trials + 1. - """ - if not valid_code(code): - return False - - code = bytes(int(code)) - for i in range(last + 1, last + trials + 1): - if compare_digest(bytes(self.hotp(counter=i)), code): - return i - return False - - def valid_totp(self, code, period=30, timestamp=None): - """Valid a TOTP code. - - :param code: A number that is less than 6 characters. - :param period: A period that a TOTP code is valid in seconds - :param timestamp: Validate TOTP at this given timestamp - """ - if not valid_code(code): - return False - return compare_digest( - bytes(self.totp(period, timestamp)), - bytes(int(code)) - ) - - @property - def encoded_secret(self): - secret = base64.b32encode(to_bytes(self.secret)) - # bytes to string - secret = secret.decode('utf-8') - # remove pad string - return secret.strip('=') - - def to_uri(self, type, label, issuer, counter=None): - """Generate the otpauth protocal string. - - :param type: Algorithm type, hotp or totp. - :param label: Label of the identifier. - :param issuer: The company, the organization or something else. - :param counter: Counter of the HOTP algorithm. - """ - type = type.lower() - - if type not in ('hotp', 'totp'): - raise ValueError('type must be hotp or totp') - - if type == 'hotp' and not counter: - raise ValueError('HOTP type authentication need counter') - - # https://code.google.com/p/google-authenticator/wiki/KeyUriFormat - url = ('otpauth://%(type)s/%(label)s?secret=%(secret)s' - '&issuer=%(issuer)s') - dct = dict( - type=type, label=label, issuer=issuer, - secret=self.encoded_secret, counter=counter - ) - ret = url % dct - if type == 'hotp': - ret = '%s&counter=%s' % (ret, counter) - return ret - - def to_google(self, type, label, issuer, counter=None): - """Generate the otpauth protocal string for Google Authenticator. - - .. deprecated:: 0.2.0 - Use :func:`to_uri` instead. - """ - warnings.warn('deprecated, use to_uri instead', DeprecationWarning) - return self.to_uri(type, label, issuer, counter) - - -def generate_hotp(secret, counter=4): - """Generate a HOTP code. - - :param secret: A secret token for the authentication. - :param counter: HOTP is a counter based algorithm. - """ - # https://tools.ietf.org/html/rfc4226 - msg = struct.pack('>Q', counter) - digest = hmac.new(to_bytes(secret), msg, hashlib.sha1).digest() - - ob = digest[19] - if PY2: - ob = ord(ob) - - pos = ob & 15 - base = struct.unpack('>I', digest[pos:pos + 4])[0] & 0x7fffffff - token = base % 1000000 - return token - - -def generate_totp(secret, period=30, timestamp=None): - """Generate a TOTP code. - - A TOTP code is an extension of HOTP algorithm. - - :param secret: A secret token for the authentication. - :param period: A period that a TOTP code is valid in seconds - :param timestamp: Current time stamp. - """ - if timestamp is None: - timestamp = time.time() - counter = int(timestamp) // period - return generate_hotp(secret, counter) - - -def to_bytes(text): - if isinstance(text, string_type): - # Python3 str -> bytes - # Python2 unicode -> str - text = text.encode('utf-8') - return text - - -def valid_code(code): - code = string_type(code) - return code.isdigit() and len(code) <= 6 - - -def compare_digest(a, b): - func = getattr(hmac, 'compare_digest', None) - if func: - return func(a, b) - - # fallback - if len(a) != len(b): - return False - - rv = 0 - if PY2: - from itertools import izip - for x, y in izip(a, b): - rv |= ord(x) ^ ord(y) - else: - for x, y in zip(a, b): - rv |= x ^ y - return rv == 0 \ No newline at end of file diff --git a/utils/serializers.py b/utils/serializers.py deleted file mode 100644 index e69de29b..00000000 diff --git a/utils/shortcuts.py b/utils/shortcuts.py index 0506ad9e..c1ad448b 100644 --- a/utils/shortcuts.py +++ b/utils/shortcuts.py @@ -1,4 +1,3 @@ -# coding=utf-8 import logging import random @@ -22,4 +21,4 @@ def rand_str(length=32, type="lower_hex"): elif type == "lower_hex": return random.choice("123456789abcdef") + get_random_string(length - 1, allowed_chars="0123456789abcdef") else: - return random.choice("123456789") + get_random_string(length - 1, allowed_chars="0123456789") \ No newline at end of file + return random.choice("123456789") + get_random_string(length - 1, allowed_chars="0123456789")