Example #1
0
File: test.py Project: teward/pyotp
    def test_provisioning_uri(self):
        hotp = pyotp.HOTP('wrn3pqx5uqxqvnqr')

        url = urlparse(
            hotp.provisioning_uri('mark@percival'))
        self.assertEqual(url.scheme, 'otpauth')
        self.assertEqual(url.netloc, 'hotp')
        self.assertEqual(url.path, '/mark%40percival')
        self.assertEqual(dict(parse_qsl(url.query)),
                         {'secret': 'wrn3pqx5uqxqvnqr', 'counter': '0'})

        url = urlparse(
            hotp.provisioning_uri('mark@percival', initial_count=12))
        self.assertEqual(url.scheme, 'otpauth')
        self.assertEqual(url.netloc, 'hotp')
        self.assertEqual(url.path, '/mark%40percival')
        self.assertEqual(dict(parse_qsl(url.query)),
                         {'secret': 'wrn3pqx5uqxqvnqr', 'counter': '12'})

        url = urlparse(
            hotp.provisioning_uri('mark@percival', issuer_name='FooCorp!'))
        self.assertEqual(url.scheme, 'otpauth')
        self.assertEqual(url.netloc, 'hotp')
        self.assertEqual(url.path, '/FooCorp%21:mark%40percival')
        self.assertEqual(dict(parse_qsl(url.query)),
                         {'secret': 'wrn3pqx5uqxqvnqr', 'counter': '0',
                          'issuer': 'FooCorp!'})

        key = 'c7uxuqhgflpw7oruedmglbrk7u6242vb'
        hotp = pyotp.HOTP(key, digits=8, digest=hashlib.sha256)
        url = urlparse(
            hotp.provisioning_uri('baco@peperina', issuer_name='FooCorp'))
        self.assertEqual(url.scheme, 'otpauth')
        self.assertEqual(url.netloc, 'hotp')
        self.assertEqual(url.path, '/FooCorp:baco%40peperina')
        self.assertEqual(dict(parse_qsl(url.query)),
                         {'secret': 'c7uxuqhgflpw7oruedmglbrk7u6242vb',
                          'counter': '0', 'issuer': 'FooCorp',
                          'digits': '8', 'algorithm': 'SHA256'})

        hotp = pyotp.HOTP(key, digits=8)
        url = urlparse(
            hotp.provisioning_uri('baco@peperina', issuer_name='Foo Corp',
                                  initial_count=10))
        self.assertEqual(url.scheme, 'otpauth')
        self.assertEqual(url.netloc, 'hotp')
        self.assertEqual(url.path, '/Foo%20Corp:baco%40peperina')
        self.assertEqual(dict(parse_qsl(url.query)),
                         {'secret': 'c7uxuqhgflpw7oruedmglbrk7u6242vb',
                          'counter': '10', 'issuer': 'Foo Corp',
                          'digits': '8'})
Example #2
0
 def get(request, phone):
     try:
         Mobile = phoneModel.objects.get(
             phone_number=phone
         )  # if Mobile already exists the take this else create New One
     except ObjectDoesNotExist:
         phoneModel.objects.create(phone_number=phone, )
         Mobile = phoneModel.objects.get(
             phone_number=phone)  # user Newly created Model
     Mobile.counter += 1  # Update Counter At every Call
     Mobile.save()  # Save the data
     keygen = generateKey()
     key = base64.b32encode(
         keygen.returnValue(phone).encode())  # Key is generated
     OTP = pyotp.HOTP(key)  # HOTP Model for OTP is created
     print(OTP.at(Mobile.counter))
     custom_params = {
         "number": phone,
         "text": f"Your one time code is: {OTP.at(Mobile.counter)}",
         "sign": "SMS Aero"
     }
     r = requests.get(
         url=SMS_AERO_URL,
         params=custom_params,
         auth=HTTPBasicAuth(SMS_AERO_USERNAME,
                            SMS_AERO_API_KEY))  #same as Http Basic auth
     # Using Multi-Threading send the OTP Using Messaging Services like Twilio or Fast2sms
     return Response({"otp": OTP.at(Mobile.counter)},
                     status=200)  # Just for demonstration
Example #3
0
    def get(request, phone):
        try:
            try:
                Mobile = Phone.objects.get(Mobile=phone)  # if Mobile already exists the take this else create New One
            except ObjectDoesNotExist:
                Phone.objects.create(
                    Mobile=phone,
                )
                Mobile = Phone.objects.get(Mobile=phone)  # user Newly created Model
            Mobile.counter += 1  # Update Counter At every Call
            Mobile.save()  # Save the data
            keygen = generateKey()
            key = base64.b32encode(keygen.returnValue(phone).encode())  # Key is generated
            OTP = pyotp.HOTP(key)  # HOTP Model for OTP is created
            print(OTP.at(Mobile.counter))

            # Your Account Sid and Auth Token from twilio.com/console
            client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)

            message = client.messages \
                .create(
                body='OTP for Parking Service is '+OTP.at(Mobile.counter),
                from_=SMS_FROM_NO,
                to='+91'+phone
            )

            print(message.sid)

            # Using Multi-Threading send the OTP Using Messaging Services like Twilio or Fast2sms
            # return Response({"OTP": OTP.at(Mobile.counter)}, status=200)  # Just for demonstration
            return Response({"message": "OTP Sent."}, status=status.HTTP_200_OK)
        except TwilioRestException:
            return Response({"message": "Trial Twilio accounts cannot send messages to unverified numbers.", "OTP": OTP.at(Mobile.counter)}, status=status.HTTP_200_OK)  # Just for demonstration
        except Exception as e:
            return Response({"Error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
Example #4
0
def confirm_otp_token(login_manager, otp=None, tmp_id=None):
	'''Confirm otp matches.'''
	if not otp:
		otp = frappe.form_dict.get('otp')
	if not otp:
		if two_factor_is_enabled_for_(login_manager.user):
			return False
		return True
	if not tmp_id:
		tmp_id = frappe.form_dict.get('tmp_id')
	hotp_token = frappe.cache().get(tmp_id + '_token')
	otp_secret = frappe.cache().get(tmp_id + '_otp_secret')
	if not otp_secret:
		raise ExpiredLoginException(_('Login session expired, refresh page to retry'))
	hotp = pyotp.HOTP(otp_secret)
	if hotp_token:
		if hotp.verify(otp, int(hotp_token)):
			frappe.cache().delete(tmp_id + '_token')
			return True
		else:
			login_manager.fail(_('Incorrect Verification code'), login_manager.user)

	totp = pyotp.TOTP(otp_secret)
	if totp.verify(otp):
		# show qr code only once
		if not frappe.db.get_default(login_manager.user + '_otplogin'):
			frappe.db.set_default(login_manager.user + '_otplogin', 1)
			delete_qrimage(login_manager.user)
		return True
	else:
		login_manager.fail(_('Incorrect Verification code'), login_manager.user)
Example #5
0
def send_user_otp(mobile=None, user=None):
    try:
        '''Authenticate using otp.'''
        from frappe.twofactor import (should_run_2fa, authenticate_for_2factor,get_otpsecret_for_,
        confirm_otp_token, send_token_via_sms, send_token_via_email)
        import pyotp, os
        if mobile:
            user = frappe.db.get_value('User', {"mobile_no":mobile},'name')
        recipients = []
        recipients = recipients + mobile.split("\n") 
        recipients = list(set(recipients))
        otp_secret = get_otpsecret_for_(user)
        token = int(pyotp.TOTP(otp_secret).now())
        hotp = pyotp.HOTP(otp_secret)
        otp = hotp.at(int(token))
        frappe.log_error(otp, "userverification")
        # otp_issuer="INGC"
        message = 'Your verification code is {otp}'.format(otp=otp)
        status = send_sms(recipients, message)
        verification_obj = {
            'token_delivery': status,
            'prompt': status and 'Enter verification code sent to {}'.format(mobile[:4] + '******' + mobile[-3:]),
            "user": user,
            "tmp_id":token
        }
        return verification_obj
    except Exception as e:		
        frappe.log_error(frappe.get_traceback(), "myjobpro.api.send_user_otp")
Example #6
0
def send_token_via_sms(otpsecret, token=None, phone_no=None):
	'''Send token as sms to user.'''
	otp_issuer = frappe.db.get_value('System Settings', 'System Settings', 'otp_issuer_name')
	try:
		from frappe.core.doctype.sms_settings.sms_settings import send_request
	except:
		return False

	if not phone_no:
		return False

	ss = frappe.get_doc('SMS Settings', 'SMS Settings')
	if not ss.sms_gateway_url:
		return False

	hotp = pyotp.HOTP(otpsecret)
	args = {
		ss.message_parameter: 'Your verification code is {}'.format(hotp.at(int(token)))
	}

	for d in ss.get("parameters"):
		args[d.parameter] = d.value

	args[ss.receiver_parameter] = phone_no

	sms_args = {
		'params': args,
		'gateway_url': ss.sms_gateway_url
	}
	enqueue(method=send_request, queue='short', timeout=300, event=None,
		async=True, job_name=None, now=False, **sms_args)
	return True
    def respond(self, request):
        rtime = time.time()
        jsonStr = request.payload
        #jsonStr = request
        dict = json.loads(jsonStr)

        hotp = pyotp.HOTP(self.groupNonce)

        timeCode = dict['timestamp'].replace(":", "")
        timeCode = timeCode.replace(" ", "")
        timeCode = timeCode.replace("-", "")
        timeCode = int(timeCode)

        groupKey = hotp.at(timeCode)
        m = hashlib.md5()
        m.update(groupKey.encode("UTF-8"))
        hashedKey = m.hexdigest()[:16]

        IV = binascii.unhexlify(dict['iv'])
        decipher = AES.new(hashedKey, AES.MODE_CBC, IV)
        unhexData = binascii.unhexlify(dict['data'])
        plainText = decipher.decrypt(unhexData)
        plainText = plainText[:-plainText[-1]]
        plainText = plainText.decode("utf-8")

        if plainText in self.database.keys():
            #Value, encrypt, json, return
            payload = self._encrypt(self.database[plainText][:-1])
            self._send(request.source[0], 'respond/',
                       defines.Codes.POST.number, payload, rtime)
            return "OK"
Example #8
0
def register(request):
    if request.method == 'POST':
        username, dominio = request.POST['email'].split('@')
        if dominio == 'inf.ufsm.br':
            try:
                User.objects.get(username=username)
                messages.warning(request, 'Esse email já está cadastrado')
            except ObjectDoesNotExist:
                hotp = pyotp.HOTP('base32secret3232')
                number = random.randrange(10000)
                # Save number of auth.
                token, created = Token.objects.get_or_create(username=username)
                token.token = number
                token.save()
                key = hotp.at(number)
                # Envia email com o token para a autenticação.
                subject = "[NCC Machine] Confirmação de email ."
                url = request.build_absolute_uri(
                    reverse('accounts:cadastro',
                            kwargs={
                                'username': username,
                                'token': str(key)
                            }))
                mensagem = "Olá, acesse a seguinte URL para continuar seu cadastro: " + url
                mfrom = settings.EMAIL_HOST_USER
                mto = [request.POST['email']]
                send_mail(subject, mensagem, mfrom, mto)
                messages.warning(
                    request,
                    'Um link foi enviado para seu email para continuar o cadastro'
                )
        else:
            messages.error(request, 'Insira um email @inf.ufsm.br')
    return render(request, 'accounts/register.html')
Example #9
0
def send_token_via_email(user, token, otp_secret, otp_issuer, subject=None, message=None):
	'''Send token to user as email.'''
	user_email = frappe.db.get_value('User', user, 'email')
	if not user_email:
		return False
	hotp = pyotp.HOTP(otp_secret)
	otp = hotp.at(int(token))
	template_args = {'otp': otp, 'otp_issuer': otp_issuer}
	if not subject:
		subject = get_email_subject_for_2fa(template_args)
	if not message:
		message = get_email_body_for_2fa(template_args)

	email_args = {
		'recipients': user_email,
		'sender': None,
		'subject': subject,
		'message': message,
		'header': [_('Verfication Code'), 'blue'],
		'delayed': False,
		'retry':3
	}

	enqueue(method=frappe.sendmail, queue='short', timeout=300, event=None,
		async=True, job_name=None, now=False, **email_args)
	return True
Example #10
0
 def check_otp(self, otp_code):
     res_user = self.env['res.users'].browse(self.env.uid)
     if res_user.aut_type2FA == 'Email' and res_user.require_2FA:
         if type(otp_code) is str and len(otp_code) == 16:
             tz_offset = self.env.user.tz_offset if self.env.user.tz_offset else False
             tz = int(tz_offset)/100 if tz_offset else 0
             now = fields.Datetime.now() + datetime.timedelta(hours=tz)
             return res_user.twoFA_code == otp_code and now < res_user.twoFA_date
     elif res_user.aut_type2FA == 'QR Code' and res_user.require_2FA:
         self.require_2FA_flag = False
         if type(otp_code) is str and len(otp_code) != 6:
             return False
         if res_user.otp_type == 'time':
             totp = pyotp.TOTP(res_user.otp_secret)
             return totp.verify(otp_code)
         elif res_user.otp_type == 'count':
             hotp = pyotp.HOTP(res_user.otp_secret)
             for i in range(0,20):
                 print(hotp.at(i), i)
             # Allow users to accidentally click 20 times more, but the code that has been used cannot be used again
             for count in range(res_user.otp_counter, res_user.otp_counter + 20):
                 val = hotp.verify(otp_code, count)
                 if count > 0 and val:
                     self.require_2FA_flag = True
                     res_user.otp_counter = count + 1
                     return True
     return False
    def get(request, phone):
        try:
            Mobile = User.objects.get(
                phone=phone
            )  # if Mobile already exists the take this else create New One
        except ObjectDoesNotExist:
            message = {
                'message':
                'Phone Number does exist please enter registered phone number'
            }
            return Response(data=message, status=400)

        Mobile.counter += 1
        Mobile.save()
        keygen = generateKey()
        key = base64.b32encode(
            keygen.returnValue(phone).encode())  # Key is generated
        OTP = pyotp.HOTP(key)

        message = client.messages \
                        .create(
                            body=f''''
                            You have recived this otp on request for password reset
                            Please click on the link below and enter the otp

                            Your one time password is:{OTP.at(Mobile.counter)}

                            http://52.201.220.252/api/otp/
                                   ''',
                            from_='+19388883481',
                            to=f'+91{Mobile}'
                        )
        return Response({"OTP": OTP.at(Mobile.counter)},
                        status=200)  # Just for demonstration
Example #12
0
def OTPVerify():
    error = None
    if request.method == "POST":
        req = request.form
        HTOP = pyotp.HOTP("JASWY3DPEHPK3PXP")
        i = 7
        a = (HTOP.at(i))
        b = (HTOP.at(i+1))
        c = (HTOP.at(i+2))
        d = (HTOP.at(i+3))
        print(a)
        if req["otp"] == a:
            return render_template('home.html')

        if req["otp"] == b:
            return render_template('home.html')

        if req["otp"] == c:
            return render_template('home.html')

        if req["otp"] == d:
            return render_template('home.html')

        else:
            errorMsg = "Wrong OTP. Please enter again."
            print(error)
            return render_template('OTP.html', error=error, errorMsg=errorMsg)
def confirm_device_otp_token():
    email = frappe.form_dict.get('email')
    tmp_id = frappe.form_dict.get('tmp_id')
    otp = frappe.form_dict.get('otp')

    if email and not frappe.db.exists('User', email):
        raise frappe.PermissionError("User does not exist")

    if not otp:
        raise frappe.PermissionError("OTP not found")

    if not tmp_id:
        raise frappe.PermissionError("ID not found")

    hotp_token = frappe.cache().get(tmp_id + '_token')
    otp_secret = frappe.cache().get(tmp_id + '_otp_secret')

    if not otp_secret:
        raise frappe.PermissionError("Login expired")

    hotp = pyotp.HOTP(otp_secret)
    if hotp_token:
        if hotp.verify(otp, int(hotp_token)):
            frappe.cache().delete(tmp_id + '_token')
            key = _generate_key(email)
            return key
        else:
            raise frappe.PermissionError("OTP does not match")

    totp = pyotp.TOTP(otp_secret)
    if totp.verify(otp):
        key = _generate_key(email)
        return key
    else:
        raise frappe.PermissionError("OTP does not match")
Example #14
0
    def _add_otp(self, name=None, otp_type=None, secret=None):
        if not name:
            self.q.put([Action.ask_input, _("Add OTP to which password?"), "", "add_otp"])
        elif not otp_type:
            screenshot = pyscreenshot.grab(childprocess=False).convert('L')
            qr_codes = zbar.Scanner().scan(screenshot)
            autodetected = 0
            for qr_code in qr_codes:
                qr_data = qr_code.data.decode()
                try:
                    pyotp.parse_uri(qr_data)
                except ValueError:
                    continue

                autodetected += 1
                self._append_password(name, qr_data)

            if autodetected == 0:
                self.q.put([Action.add_error, _("Could not detect any valid OTP QR codes on your screen. Continuing with manual configuration...")])
                self.q.put([Action.ask_choice, _("Use which OTP type?"), ["TOTP", "HOTP"], "add_otp {}".format(name)])
            else:
                self.q.put([Action.add_message, _("Detected and added {} valid OTP QR code(s) on your screen.").format(str(autodetected))])
                return
        elif not secret:
            self.q.put([Action.ask_input, _("What is the OTP secret?"), "", "add_otp {} {}".format(name, otp_type)])
        else:
            if otp_type == "TOTP":
                otp_uri = pyotp.TOTP(secret).provisioning_uri()
            elif otp_type == "HOTP":
                otp_uri = pyotp.HOTP(secret).provisioning_uri()
            else:
                return

            self._append_password(name, otp_uri)
Example #15
0
    def post(request, phone):
        try:
            Mobile = phoneModel.objects.get(phone_number=phone)
        except ObjectDoesNotExist:
            return Response("User does not exist", status=404)  # False Call

        keygen = generateKey()
        key = base64.b32encode(
            keygen.returnValue(phone).encode())  # Generating Key
        OTP = pyotp.HOTP(key)  # HOTP Model
        if OTP.verify(request.data["otp"],
                      Mobile.counter):  # Verifying the OTP
            Mobile.isVerified = True
            Mobile.save()
            first_name = request.data["first_name"]
            last_name = request.data['last_name']
            phone_number = request.data['phone_number']
            password = request.data['password']
            user = Account.objects.create_user(first_name=first_name,
                                               last_name=last_name,
                                               password=password,
                                               phone_number=phone_number)
            user.save()
            account = Profile.objects.create(account=user, visit_counter=0)
            account.save()
            return Response("You are authorised", status=200)
        return Response("OTP is wrong", status=400)
Example #16
0
def cadastrar(request, token, username):
    hotp = pyotp.HOTP('base32secret3232')
    crip = Token.objects.get(username=username)
    if not hotp.verify(token, crip.token):
        messages.error(
            request,
            'Token invalido, não foi possível fazer a confirmação de email. Tente novamente!'
        )
        return redirect('index')
    else:
        form = UserAdminCreationForm()
        if request.method == 'POST':
            form = UserAdminCreationForm(request.POST)
            if form.is_valid():
                user = form.save(commit=False)
                user.username = username
                user.email = username + '@inf.ufsm.br'
                user.save()
                raw_password = form.cleaned_data.get('password1')
                user = authenticate(username=user.username,
                                    password=raw_password)
                login(request, user)
                messages.success(request, 'Usuario criado com sucesso')
                return redirect('accounts:index')
            else:
                messages.error(request, 'Dados invalidos')
    return render(request, 'accounts/cadastro.html', {
        'form': form,
        'token': token,
        'username': username
    })
Example #17
0
    def verify_signup(self, request, format='json'):
        validator = SignUpVerificationValidator(data=request.query_params)
        if not validator.is_valid():
            return Response(validator.errors,
                            status=status.HTTP_400_BAD_REQUEST)
        if validator.is_valid():
            validated_data = validator.validated_data
            code = validated_data['code']
            user_id = int(validated_data['user_id'])

            confirm_token = ConfirmToken.objects.get(user__id=user_id,
                                                     kind=SIGNUP_TOKEN)

            user = User.objects.get(id=int(user_id))
            date_time = confirm_token.token_epires_at
            key = confirm_token.token_hash
            if (timezone.now() < date_time):
                counter = int(user.id)

                hotp = pyotp.HOTP(key)

                if int(code) == int(hotp.at(counter)):
                    user.is_active = True
                    user.save()
                    confirm_token.delete()
                    data = get_tokens_plus_user(user, request)
                    data["message"] = "Account Activated Successfully"
                    return Response(data, status=status.HTTP_200_OK)
                else:
                    return Response({"message": "Invalid Code"},
                                    status=status.HTTP_400_BAD_REQUEST)
            else:
                return Response({"message": "Code Expired"},
                                status=status.HTTP_400_BAD_REQUEST)
Example #18
0
def check_token(token, secret, counter):
    hotp = pyotp.HOTP(secret)

    for i in range(1, 10):
        if hotp.verify(token, (counter + i)):
            return counter + i
    return 0
Example #19
0
    def _add_otp(self, name=None, otp_type=None, secret=None):
        if not hasattr(pyotp, "parse_uri"):
            self.q.put([
                Action.critical_error,
                _("pyotp lib doesn't support this yet")
            ])
            return
        if not name:
            self.q.put([
                Action.ask_input,
                _("What password should OTP be added to?"), "", "add_otp"
            ])
        elif not otp_type:
            screenshot = pyscreenshot.grab(childprocess=False).convert('L')
            qr_codes = zbar.Scanner().scan(screenshot)
            autodetected = 0
            for qr_code in qr_codes:
                qr_data = qr_code.data.decode()
                try:
                    pyotp.parse_uri(qr_data)
                except ValueError:
                    continue

                autodetected += 1
                self._append_password(name, qr_data)

            if autodetected == 0:
                self.q.put([
                    Action.add_error,
                    _("No valid OTP QR codes detected on your screen. Configuring manually…"
                      )
                ])
                self.q.put([
                    Action.ask_choice,
                    _("Which OTP type should be used?"), ["TOTP", "HOTP"],
                    "add_otp {}".format(name)
                ])
            else:
                self.q.put([
                    Action.add_message,
                    _("Detected and added {} valid OTP QR code(s) on your screen."
                      ).format(str(autodetected))
                ])
                return
        elif not secret:
            self.q.put([
                Action.ask_input,
                _("What is the OTP secret?"), "",
                "add_otp {} {}".format(name, otp_type)
            ])
        else:
            if otp_type == "TOTP":
                otp_uri = pyotp.TOTP(secret).provisioning_uri()
            elif otp_type == "HOTP":
                otp_uri = pyotp.HOTP(secret).provisioning_uri()
            else:
                return

            self._append_password(name, otp_uri)
Example #20
0
 def check_token(self, user, token):
     if not (user and token):
         return False
     key = base64.b32encode(self._make_hash_value(user).encode())
     OTP = pyotp.HOTP(key)  # HOTP Model
     if OTP.verify(token, user.pk):  # Verifying the OTP
         return True
     return False
Example #21
0
 def get(self, username):
     try:
         userinfo = db.get_user(username)
         hotp = pyotp.HOTP(userinfo.otp_secret)
         otp_key = hotp.at(userinfo.hotp_counter)
         self.write(str(otp_key))
     except db.User.DoesNotExist:
         self.send_error(404)
Example #22
0
    def create(self, country_code: str, phone_number: int):
        secret = self._create_secret(secret=pyotp.random_base32(length=32))
        counter = self._create_counter()

        hotp = pyotp.HOTP(secret, digits=self._digits)
        self._send_sms(sms_code=hotp.at(counter),
                       country_code=country_code,
                       phone_number=phone_number)
Example #23
0
def _validate_passcode(passcode):
    passcode = int(passcode)
    if session.get('two_factor_counter'):
        hotp = pyotp.HOTP(app.config['OTP_SECRET'])
        return hotp.verify(passcode, session['two_factor_counter'])
    else:
        totp = pyotp.TOTP(app.config['OTP_SECRET'])
        return totp.verify(passcode)
Example #24
0
 def test_other_secret(self):
     hotp = pyotp.HOTP(
         'N3OVNIBRERIO5OHGVCMDGS4V4RJ3AUZOUN34J6FRM4P6JIFCG3ZA')
     self.assertEqual(hotp.at(0), '737863')
     self.assertEqual(hotp.at(1), '390601')
     self.assertEqual(hotp.at(2), '363354')
     self.assertEqual(hotp.at(3), '936780')
     self.assertEqual(hotp.at(4), '654019')
Example #25
0
 def __init__(self, a, b, c, char, exp):
     self.a, self.b, self.c = a, b, c
     self.char, self.exp = char, exp
     print(self)
     f = open("otp_seed.txt", "r")
     seed = f.readline().strip()
     f.close()
     self.hotp = pyotp.HOTP(seed)
Example #26
0
    def testHOTPRateLimit(self):
        logger.debug('Running testHOTPRateLimit')

        backends = getBackends()
        # Save custom state for HOTP user, as some backends rely on it to trigger HOTP mode
        state = totpcgi.GAUserState()
        state.counter = 1
        setCustomState(state, 'hotp')

        gau = totpcgi.GAUser('hotp', backends)
        secret = backends.secret_backend.get_user_secret(gau.user)

        hotp = pyotp.HOTP(secret.otp.secret)
        token = hotp.at(1)
        self.assertEqual(gau.verify_token(token), 'Valid HOTP token used')
        # counter is now at 2

        token = '555555'

        # We now fail 4 times consecutively
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)
        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)

        # We should now get a rate-limited error
        with self.assertRaisesRegex(totpcgi.VerifyFailed, 'Rate-limit'):
            gau.verify_token(token)

        # Same with a valid token
        with self.assertRaisesRegex(totpcgi.VerifyFailed, 'Rate-limit'):
            gau.verify_token(hotp.at(2))

        # Make sure we recover from rate-limiting correctly
        old_timestamp = secret.timestamp - (31 + (secret.rate_limit[1] * 10))
        state = totpcgi.GAUserState()
        state.fail_timestamps = [
            old_timestamp, old_timestamp, old_timestamp, old_timestamp
        ]
        state.counter = 2
        setCustomState(state, 'hotp')

        with self.assertRaisesRegex(totpcgi.VerifyFailed,
                                    'HOTP token failed to verify'):
            gau.verify_token(token)

        # Valid token should work, too
        setCustomState(state, 'hotp')
        self.assertEqual(gau.verify_token(hotp.at(2)), 'Valid HOTP token used')
        cleanState('hotp')
Example #27
0
def do_verify():
    # handle username/password
    # TODO: CSRF protection
    username = request.forms.get('username')
    password = request.forms.get('password')
    if username and password:
        logging.info('Verifying username %s and password...', username)
        handler = OdooAuthHandler()
        data, session_id = handler.check_login(username, password)
        if session_id:
            hotp = pyotp.HOTP(HOTP_SECRET)
            counter, code = db.next_hotp_id(session_id)
            key = hotp.at(counter)
            if not send_mail(username, key):
                message = 'Mail with security code not sent.'
                logging.error(message)
                return template('login', dict(theme_params, error=message))
            return template(
                'hotp', dict(theme_params.items(), counter=counter, code=code))
        else:
            # TODO: brute force protection
            #       (block for X minutes after X attempts)
            message = 'Invalid username or password.'
            logging.info(message)
            return template('login', dict(theme_params, error=message))

    # check HOTP
    counter = request.forms.get('counter')
    code = request.forms.get('code')
    hotp_code = request.forms.get('hotp_code')
    if code and counter and hotp_code:
        hotp = pyotp.HOTP(HOTP_SECRET)
        if not hotp.verify(hotp_code, int(counter)):
            message = 'Invalid security code.'
            return template('login', dict(theme_params, error=message))
        session_id = db.verify_code_and_expiry(counter, code)
        if not session_id:
            message = 'Invalid security code (2).'
            return template('login', dict(theme_params, error=message))
        db.save_session(session_id, EXPIRY_INTERVAL)
        logging.info('Setting session cookie: %s', session_id)
        response.set_cookie("session_id", session_id, path='/')
        return redirect('/')

    return redirect('/')
Example #28
0
def counter_based_otp():
    hotp = pyotp.HOTP('base32secret3232')
    hotp.at(0)  # => '260182'
    hotp.at(1)  # => '055283'
    hotp.at(1401)  # => '316439'

    # OTP verified with a counter
    hotp.verify('316439', 1401)  # => True
    hotp.verify('316439', 1402)  # => False
Example #29
0
    def verify(self, sms_code: int, phone_number: int) -> str:
        secret = self._get_secret()
        count = self._get_counter()

        if count and secret:
            hotp = pyotp.HOTP(secret, digits=self._digits)
            if hotp.verify(sms_code, count):
                return self._create_token(phone_number=phone_number)
        return None
Example #30
0
def testHOTPBasedComm():
    hotp = pyotp.HOTP('base32secret3232')
    print(hotp.at(0))  # => '260182'
    print(hotp.at(1))  # => '055283'
    print(hotp.at(1401))  # => '316439'

    # OTP verified with a counter
    print(hotp.verify('316439', 1401))  # => True
    print(hotp.verify('316439', 1402))  # => False