add bitcoin to address model
This commit is contained in:
parent
0071013d71
commit
1eac8809e8
|
@ -11,7 +11,10 @@ Django-Cryptolock
|
|||
.. image:: https://coveralls.io/repos/github/dethos/django-cryptolock/badge.svg
|
||||
:target: https://coveralls.io/github/dethos/django-cryptolock
|
||||
|
||||
Django authentication using cryptocurrency wallets
|
||||
Django authentication using cryptocurrency wallets.
|
||||
|
||||
**DISCLAIMER:** This package is still in an early stage of development. It isn't meant to be
|
||||
used on any production scenario yet (in other words, only test projects for now).
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
|
|
@ -40,3 +40,17 @@ class MoneroAddressBackend(ModelBackend):
|
|||
return stored_address.user
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class BitcoinAddressBackend(ModelBackend):
|
||||
"""Custom Bitcoin-BitId authentication backend."""
|
||||
|
||||
def authenticate(
|
||||
self, request, address=None, challenge=None, signature=None, **kwargs
|
||||
):
|
||||
"""
|
||||
Validates the provided signature for the given Bitcoin address and challenge.
|
||||
|
||||
This method does not rely on any external components, everything is done locally.
|
||||
"""
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 2.2.5 on 2020-02-18 19:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_cryptolock', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='address',
|
||||
name='network',
|
||||
field=models.PositiveSmallIntegerField(choices=[(1, 'Monero'), (2, 'Bitcoin')], default=1),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='address',
|
||||
name='address',
|
||||
field=models.CharField(max_length=106, unique=True),
|
||||
),
|
||||
]
|
|
@ -3,19 +3,24 @@
|
|||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from model_utils.models import TimeStampedModel
|
||||
|
||||
from .validators import validate_monero_address
|
||||
from .validators import validate_monero_address, validate_bitcoin_address
|
||||
|
||||
|
||||
class Address(TimeStampedModel):
|
||||
"""Addresses that belong to a given user account."""
|
||||
|
||||
NETWORK_MONERO = 1
|
||||
NETWORK_BITCOIN = 2
|
||||
|
||||
NETWORKS = ((NETWORK_MONERO, "Monero"), (NETWORK_BITCOIN, "Bitcoin"))
|
||||
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
address = models.CharField(
|
||||
max_length=106, validators=[validate_monero_address], unique=True
|
||||
)
|
||||
network = models.PositiveSmallIntegerField(choices=NETWORKS, default=NETWORK_MONERO)
|
||||
address = models.CharField(max_length=106, unique=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta definition for Address."""
|
||||
|
@ -26,3 +31,12 @@ class Address(TimeStampedModel):
|
|||
def __str__(self):
|
||||
"""Unicode representation of Address."""
|
||||
return self.address
|
||||
|
||||
def clean(self):
|
||||
try:
|
||||
if self.network == self.NETWORK_MONERO:
|
||||
validate_monero_address(self.address)
|
||||
else:
|
||||
validate_bitcoin_address(self.address)
|
||||
except ValidationError:
|
||||
raise ValidationError(_("Invalid address for the given network"))
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.conf import settings
|
||||
|
||||
from monero.address import Address
|
||||
from pybitid.bitid import address_valid
|
||||
|
||||
|
||||
def validate_monero_address(value):
|
||||
|
@ -24,3 +25,14 @@ def validate_monero_address(value):
|
|||
raise ValidationError(_("Invalid address for stagenet"))
|
||||
elif network == "testnet" and not address.is_testnet():
|
||||
raise ValidationError(_("Invalid address for testnet"))
|
||||
|
||||
|
||||
def validate_bitcoin_address(value):
|
||||
network = getattr(settings, "DJCL_BITCOIN_NETWORK", None)
|
||||
if not network:
|
||||
raise ValidationError(
|
||||
_("Please configure the monero network in the settings file")
|
||||
)
|
||||
testnet = True if network == "testnet" else False
|
||||
if not address_valid(value, is_testnet=testnet):
|
||||
raise ValidationError(_(f"Invalid address for {network}"))
|
||||
|
|
|
@ -2,3 +2,5 @@ django>=2.2
|
|||
django-model-utils>=2.0
|
||||
monero>=0.6
|
||||
python-monerorpc>=0.5.5
|
||||
python-bitcoinaddress>=0.2.2
|
||||
pybitid>=0.0.4
|
||||
|
|
|
@ -19,30 +19,51 @@ VALID_MONERO_MAINNET_ADDR = "45D8b4XiUdz86FwztAJHVeLnQqGHQUqiHSwZe6rXFHSoXw522dP
|
|||
VALID_MONERO_STAGENET_ADDR = "55LTR8KniP4LQGJSPtbYDacR7dz8RBFnsfAKMaMuwUNYX6aQbBcovzDPyrQF9KXF9tVU6Xk3K8no1BywnJX6GvZX8yJsXvt"
|
||||
VALID_MONERO_TESTNET_ADDR = "9vmn8Vyxh6JEVmPr4qTcj3ND3FywDpMXH2fVLLEARyKCJTc3jWjxeWcbRNcaa57Bj36cARBSfWnfS89oFVKBBvGTAegdRxG"
|
||||
|
||||
VALID_BITCOIN_TESTNET_ADDR = "n47QBape2PcisN2mkHR2YnhqoBr56iPhJh"
|
||||
VALID_BITCOIN_MAINNET_ADDR = "1AUeWMGD9hDYtAhZGZLmDjEzKSrPow4zNt"
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_valid_mainnet_address(settings):
|
||||
def test_valid_monero_mainnet_address(settings):
|
||||
settings.DJCL_MONERO_NETWORK = "mainnet"
|
||||
|
||||
addr = mommy.make(Address, address=VALID_MONERO_MAINNET_ADDR)
|
||||
addr.full_clean()
|
||||
|
||||
|
||||
def test_valid_stagenet_addr(settings):
|
||||
def test_valid_monero_stagenet_addr(settings):
|
||||
settings.DJCL_MONERO_NETWORK = "stagenet"
|
||||
|
||||
addr = mommy.make(Address, address=VALID_MONERO_STAGENET_ADDR)
|
||||
addr.full_clean()
|
||||
|
||||
|
||||
def test_valid_testnet_addr(settings):
|
||||
def test_valid_monero_testnet_addr(settings):
|
||||
settings.DJCL_MONERO_NETWORK = "testnet"
|
||||
|
||||
addr = mommy.make(Address, address=VALID_MONERO_TESTNET_ADDR)
|
||||
addr.full_clean()
|
||||
|
||||
|
||||
def test_valid_bitcoin_mainnet_address(settings):
|
||||
settings.DJCL_BITCOIN_NETWORK = "mainnet"
|
||||
|
||||
addr = mommy.make(
|
||||
Address, address=VALID_BITCOIN_MAINNET_ADDR, network=Address.NETWORK_BITCOIN
|
||||
)
|
||||
addr.full_clean()
|
||||
|
||||
|
||||
def test_valid_bitcoin_testnet_address(settings):
|
||||
settings.DJCL_BITCOIN_NETWORK = "testnet"
|
||||
|
||||
addr = mommy.make(
|
||||
Address, address=VALID_BITCOIN_TESTNET_ADDR, network=Address.NETWORK_BITCOIN
|
||||
)
|
||||
addr.full_clean()
|
||||
|
||||
|
||||
def test_invalid_address():
|
||||
bad_addr = "Verywrongaddress"
|
||||
addr = mommy.make(Address, address=bad_addr)
|
||||
|
@ -51,23 +72,38 @@ def test_invalid_address():
|
|||
addr.full_clean()
|
||||
|
||||
assert (
|
||||
"{} is not a valid address".format(bad_addr)
|
||||
in error.value.message_dict["address"]
|
||||
"Invalid address for the given network" in error.value.message_dict["__all__"]
|
||||
)
|
||||
|
||||
|
||||
def test_wrong_network_address(settings):
|
||||
def test_wrong_monero_network_address(settings):
|
||||
settings.DJCL_MONERO_NETWORK = "stagenet"
|
||||
addr = mommy.make(Address, address=VALID_MONERO_MAINNET_ADDR)
|
||||
|
||||
with pytest.raises(ValidationError) as error:
|
||||
addr.full_clean()
|
||||
|
||||
assert "Invalid address for stagenet" in error.value.message_dict["address"]
|
||||
assert (
|
||||
"Invalid address for the given network" in error.value.message_dict["__all__"]
|
||||
)
|
||||
|
||||
|
||||
def test_wrong_bitcoin_network_address(settings):
|
||||
settings.DJCL_MONERO_NETWORK = "testnet"
|
||||
addr = mommy.make(
|
||||
Address, address=VALID_BITCOIN_MAINNET_ADDR, network=Address.NETWORK_BITCOIN
|
||||
)
|
||||
|
||||
with pytest.raises(ValidationError) as error:
|
||||
addr.full_clean()
|
||||
|
||||
assert (
|
||||
"Invalid address for the given network" in error.value.message_dict["__all__"]
|
||||
)
|
||||
|
||||
|
||||
def test_address_is_unique():
|
||||
addr = mommy.make(Address, address=VALID_MONERO_MAINNET_ADDR)
|
||||
mommy.make(Address, address=VALID_MONERO_MAINNET_ADDR)
|
||||
|
||||
with pytest.raises(IntegrityError):
|
||||
mommy.make(Address, address=VALID_MONERO_MAINNET_ADDR)
|
||||
|
|
Loading…
Reference in New Issue