diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 81b8203..a32c86b --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ .env .DS_Store __pycache__ -db.sqlite3 \ No newline at end of file +db.sqlite3 +._.DS_Store +._src +env \ No newline at end of file diff --git a/base/__init__.py b/base/__init__.py old mode 100644 new mode 100755 diff --git a/base/admin.py b/base/admin.py old mode 100644 new mode 100755 diff --git a/base/apps.py b/base/apps.py old mode 100644 new mode 100755 diff --git a/base/dependencies/__init__.py b/base/dependencies/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/base/dependencies/bchconvert.py b/base/dependencies/bchconvert.py new file mode 100755 index 0000000..190bc64 --- /dev/null +++ b/base/dependencies/bchconvert.py @@ -0,0 +1,129 @@ +from dependencies.crypto import * +from base58 import b58decode_check, b58encode_check +import sys + +class InvalidAddress(Exception): + pass + + +class Address: + VERSION_MAP = { + 'legacy': [ + ('P2SH', 5, False), + ('P2PKH', 0, False), + ('P2SH-TESTNET', 196, True), + ('P2PKH-TESTNET', 111, True) + ], + 'cash': [ + ('P2SH', 8, False), + ('P2PKH', 0, False), + ('P2SH-TESTNET', 8, True), + ('P2PKH-TESTNET', 0, True) + ] + } + MAINNET_PREFIX = 'bitcoincash' + TESTNET_PREFIX = 'bchtest' + + def __init__(self, version, payload, prefix=None): + self.version = version + self.payload = payload + if prefix: + self.prefix = prefix + else: + if Address._address_type('cash', self.version)[2]: + self.prefix = self.TESTNET_PREFIX + else: + self.prefix = self.MAINNET_PREFIX + + def __str__(self): + return 'version: {}\npayload: {}\nprefix: {}'.format(self.version, self.payload, self.prefix) + + def legacy_address(self): + version_int = Address._address_type('legacy', self.version)[1] + return b58encode_check(Address.code_list_to_string([version_int] + self.payload)) + + def cash_address(self): + version_int = Address._address_type('cash', self.version)[1] + payload = [version_int] + self.payload + payload = convertbits(payload, 8, 5) + checksum = calculate_checksum(self.prefix, payload) + return self.prefix + ':' + b32encode(payload + checksum) + + @staticmethod + def code_list_to_string(code_list): + if sys.version_info > (3, 0): + output = bytes() + for code in code_list: + output += bytes([code]) + else: + output = '' + for code in code_list: + output += chr(code) + return output + + @staticmethod + def _address_type(address_type, version): + for mapping in Address.VERSION_MAP[address_type]: + if mapping[0] == version or mapping[1] == version: + return mapping + raise InvalidAddress('Could not determine address version') + + @staticmethod + def from_string(address_string): + try: + address_string = str(address_string) + except Exception: + raise InvalidAddress('Expected string as input') + if ':' not in address_string: + return Address._legacy_string(address_string) + else: + return Address._cash_string(address_string) + + @staticmethod + def _legacy_string(address_string): + try: + decoded = bytearray(b58decode_check(address_string)) + except ValueError: + raise InvalidAddress('Could not decode legacy address') + version = Address._address_type('legacy', decoded[0])[0] + payload = list() + for letter in decoded[1:]: + payload.append(letter) + return Address(version, payload) + + @staticmethod + def _cash_string(address_string): + if address_string.upper() != address_string and address_string.lower() != address_string: + raise InvalidAddress('Cash address contains uppercase and lowercase characters') + address_string = address_string.lower() + colon_count = address_string.count(':') + if colon_count == 0: + address_string = Address.MAINNET_PREFIX + ':' + address_string + elif colon_count > 1: + raise InvalidAddress('Cash address contains more than one colon character') + prefix, base32string = address_string.split(':') + decoded = b32decode(base32string) + if not verify_checksum(prefix, decoded): + raise InvalidAddress('Bad cash address checksum') + converted = convertbits(decoded, 5, 8) + version = Address._address_type('cash', converted[0])[0] + if prefix == Address.TESTNET_PREFIX: + version += '-TESTNET' + payload = converted[1:-6] + return Address(version, payload, prefix) + + +def to_cash_address(address): + return Address.from_string(address).cash_address() + + +def to_legacy_address(address): + return Address.from_string(address).legacy_address() + + +def is_valid(address): + try: + Address.from_string(address) + return True + except InvalidAddress: + return False diff --git a/base/dependencies/crypto.py b/base/dependencies/crypto.py new file mode 100755 index 0000000..2e32f9e --- /dev/null +++ b/base/dependencies/crypto.py @@ -0,0 +1,70 @@ +CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' + + +def polymod(values): + chk = 1 + generator = [ + (0x01, 0x98f2bc8e61), + (0x02, 0x79b76d99e2), + (0x04, 0xf33e5fb3c4), + (0x08, 0xae2eabe2a8), + (0x10, 0x1e4f43e470)] + for value in values: + top = chk >> 35 + chk = ((chk & 0x07ffffffff) << 5) ^ value + for i in generator: + if top & i[0] != 0: + chk ^= i[1] + return chk ^ 1 + + +def prefix_expand(prefix): + return [ord(x) & 0x1f for x in prefix] + [0] + + +def calculate_checksum(prefix, payload): + poly = polymod(prefix_expand(prefix) + payload + [0, 0, 0, 0, 0, 0, 0, 0]) + out = list() + for i in range(8): + out.append((poly >> 5 * (7 - i)) & 0x1f) + return out + + +def verify_checksum(prefix, payload): + return polymod(prefix_expand(prefix) + payload) == 0 + + +def b32decode(inputs): + out = list() + for letter in inputs: + out.append(CHARSET.find(letter)) + return out + + +def b32encode(inputs): + out = '' + for char_code in inputs: + out += CHARSET[char_code] + return out + + +def convertbits(data, frombits, tobits, pad=True): + acc = 0 + bits = 0 + ret = [] + maxv = (1 << tobits) - 1 + max_acc = (1 << (frombits + tobits - 1)) - 1 + for value in data: + if value < 0 or (value >> frombits): + return None + acc = ((acc << frombits) | value) & max_acc + bits += frombits + while bits >= tobits: + bits -= tobits + ret.append((acc >> bits) & maxv) + if pad: + if bits: + ret.append((acc << (tobits - bits)) & maxv) + elif bits >= frombits or ((acc << (tobits - bits)) & maxv): + return None + return ret diff --git a/base/dependencies/moneropy.py b/base/dependencies/moneropy.py new file mode 100755 index 0000000..a05aaed --- /dev/null +++ b/base/dependencies/moneropy.py @@ -0,0 +1,185 @@ +# MoneroPy - A python toolbox for Monero +# Copyright (C) 2016 The MoneroPy Developers. +# +# MoneroPy is released under the BSD 3-Clause license. Use and redistribution of +# this software is subject to the license terms in the LICENSE file found in the +# top-level directory of this distribution. +# +# Modified by emesik and rooterkyberian: +# + optimized +# + proper exceptions instead of returning errors as results + +__alphabet = [ + ord(s) for s in "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" +] +__b58base = 58 +__UINT64MAX = 2 ** 64 +__encodedBlockSizes = [0, 2, 3, 5, 6, 7, 9, 10, 11] +__fullBlockSize = 8 +__fullEncodedBlockSize = 11 + + +def _hexToBin(hex_): + if len(hex_) % 2 != 0: + raise ValueError("Hex string has invalid length: %d" % len(hex_)) + return [int(hex_[i : i + 2], 16) for i in range(0, len(hex_), 2)] + + +def _binToHex(bin_): + return "".join("%02x" % int(b) for b in bin_) + + +def _uint8be_to_64(data): + if not (1 <= len(data) <= 8): + raise ValueError("Invalid input length: %d" % len(data)) + + res = 0 + for b in data: + res = res << 8 | b + return res + + +def _uint64_to_8be(num, size): + if size < 1 or size > 8: + raise ValueError("Invalid input length: %d" % size) + res = [0] * size + + twopow8 = 2 ** 8 + for i in range(size - 1, -1, -1): + res[i] = num % twopow8 + num = num // twopow8 + + return res + + +def encode_block(data, buf, index): + l_data = len(data) + + if l_data < 1 or l_data > __fullEncodedBlockSize: + raise ValueError("Invalid block length: %d" % l_data) + + num = _uint8be_to_64(data) + i = __encodedBlockSizes[l_data] - 1 + + while num > 0: + remainder = num % __b58base + num = num // __b58base + buf[index + i] = __alphabet[remainder] + i -= 1 + + return buf + + +def encode(hex): + """Encode hexadecimal string as base58 (ex: encoding a Monero address).""" + data = _hexToBin(hex) + l_data = len(data) + + if l_data == 0: + return "" + + full_block_count = l_data // __fullBlockSize + last_block_size = l_data % __fullBlockSize + res_size = ( + full_block_count * __fullEncodedBlockSize + __encodedBlockSizes[last_block_size] + ) + + res = bytearray([__alphabet[0]] * res_size) + + for i in range(full_block_count): + res = encode_block( + data[(i * __fullBlockSize) : (i * __fullBlockSize + __fullBlockSize)], + res, + i * __fullEncodedBlockSize, + ) + + if last_block_size > 0: + res = encode_block( + data[ + (full_block_count * __fullBlockSize) : ( + full_block_count * __fullBlockSize + last_block_size + ) + ], + res, + full_block_count * __fullEncodedBlockSize, + ) + + return bytes(res).decode("ascii") + + +def decode_block(data, buf, index): + l_data = len(data) + + if l_data < 1 or l_data > __fullEncodedBlockSize: + raise ValueError("Invalid block length: %d" % l_data) + + res_size = __encodedBlockSizes.index(l_data) + if res_size <= 0: + raise ValueError("Invalid block size: %d" % res_size) + + res_num = 0 + order = 1 + for i in range(l_data - 1, -1, -1): + digit = __alphabet.index(data[i]) + if digit < 0: + raise ValueError("Invalid symbol: %s" % data[i]) + + product = order * digit + res_num + if product > __UINT64MAX: + raise ValueError( + "Overflow: %d * %d + %d = %d" % (order, digit, res_num, product) + ) + + res_num = product + order = order * __b58base + + if res_size < __fullBlockSize and 2 ** (8 * res_size) <= res_num: + raise ValueError("Overflow: %d doesn't fit in %d bit(s)" % (res_num, res_size)) + + tmp_buf = _uint64_to_8be(res_num, res_size) + buf[index : index + len(tmp_buf)] = tmp_buf + + return buf + + +def decode(enc): + """Decode a base58 string (ex: a Monero address) into hexidecimal form.""" + enc = bytearray(enc, encoding="ascii") + l_enc = len(enc) + + if l_enc == 0: + return "" + + full_block_count = l_enc // __fullEncodedBlockSize + last_block_size = l_enc % __fullEncodedBlockSize + try: + last_block_decoded_size = __encodedBlockSizes.index(last_block_size) + except ValueError: + raise ValueError("Invalid encoded length: %d" % l_enc) + + data_size = full_block_count * __fullBlockSize + last_block_decoded_size + + data = bytearray(data_size) + for i in range(full_block_count): + data = decode_block( + enc[ + (i * __fullEncodedBlockSize) : ( + i * __fullEncodedBlockSize + __fullEncodedBlockSize + ) + ], + data, + i * __fullBlockSize, + ) + + if last_block_size > 0: + data = decode_block( + enc[ + (full_block_count * __fullEncodedBlockSize) : ( + full_block_count * __fullEncodedBlockSize + last_block_size + ) + ], + data, + full_block_count * __fullBlockSize, + ) + + return _binToHex(data) diff --git a/base/dependencies/request_api.py b/base/dependencies/request_api.py new file mode 100755 index 0000000..e7ee139 --- /dev/null +++ b/base/dependencies/request_api.py @@ -0,0 +1,36 @@ +import requests + +#from dependencies.request_api import RequestsApi +#call = RequestsApi("https://google.com") +#r = call.get("/") + +class RequestsApi: + def __init__(self, base_url, **kwargs): + self.base_url = base_url + self.session = requests.Session() + for arg in kwargs: + if isinstance(kwargs[arg], dict): + kwargs[arg] = self.deep_merge(getattr(self.session, arg), kwargs[arg]) + setattr(self.session, arg, kwargs[arg]) + + def request(self, method, url, **kwargs): + return self.session.request(method, self.base_url+url, allow_redirects = False, **kwargs) + + def head(self, url, **kwargs): + return self.session.head(self.base_url+url, allow_redirects = False, **kwargs) + + def get(self, url, **kwargs): + return self.session.get(self.base_url+url, allow_redirects = False, **kwargs) + + def post(self, url, **kwargs): + return self.session.post(self.base_url+url, allow_redirects = False, **kwargs) + + @staticmethod + def deep_merge(source, destination):< + for key, value in source.items(): + if isinstance(value, dict): + node = destination.setdefault(key, {}) + RequestsApi.deep_merge(value, node) + else: + destination[key] = value + return destination \ No newline at end of file diff --git a/base/dependencies/segwit_addr.py b/base/dependencies/segwit_addr.py new file mode 100755 index 0000000..84c7241 --- /dev/null +++ b/base/dependencies/segwit_addr.py @@ -0,0 +1,139 @@ + +# Copyright (c) 2017, 2020 Pieter Wuille +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Reference implementation for Bech32/Bech32m and segwit addresses.""" + + +from enum import Enum + +class Encoding(Enum): + """Enumeration type to list the various supported encodings.""" + BECH32 = 1 + BECH32M = 2 + +CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +BECH32M_CONST = 0x2bc830a3 + +def bech32_polymod(values): + """Internal function that computes the Bech32 checksum.""" + generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] + chk = 1 + for value in values: + top = chk >> 25 + chk = (chk & 0x1ffffff) << 5 ^ value + for i in range(5): + chk ^= generator[i] if ((top >> i) & 1) else 0 + return chk + + +def bech32_hrp_expand(hrp): + """Expand the HRP into values for checksum computation.""" + return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] + + +def bech32_verify_checksum(hrp, data): + """Verify a checksum given HRP and converted data characters.""" + const = bech32_polymod(bech32_hrp_expand(hrp) + data) + if const == 1: + return Encoding.BECH32 + if const == BECH32M_CONST: + return Encoding.BECH32M + return None + +def bech32_create_checksum(hrp, data, spec): + """Compute the checksum values given HRP and data.""" + values = bech32_hrp_expand(hrp) + data + const = BECH32M_CONST if spec == Encoding.BECH32M else 1 + polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const + return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] + + +def bech32_encode(hrp, data, spec): + """Compute a Bech32 string given HRP and data values.""" + combined = data + bech32_create_checksum(hrp, data, spec) + return hrp + '1' + ''.join([CHARSET[d] for d in combined]) + +def bech32_decode(bech): + """Validate a Bech32/Bech32m string, and determine HRP and data.""" + if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or + (bech.lower() != bech and bech.upper() != bech)): + return (None, None, None) + bech = bech.lower() + pos = bech.rfind('1') + if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: + return (None, None, None) + if not all(x in CHARSET for x in bech[pos+1:]): + return (None, None, None) + hrp = bech[:pos] + data = [CHARSET.find(x) for x in bech[pos+1:]] + spec = bech32_verify_checksum(hrp, data) + if spec is None: + return (None, None, None) + return (hrp, data[:-6], spec) + +def convertbits(data, frombits, tobits, pad=True): + """General power-of-2 base conversion.""" + acc = 0 + bits = 0 + ret = [] + maxv = (1 << tobits) - 1 + max_acc = (1 << (frombits + tobits - 1)) - 1 + for value in data: + if value < 0 or (value >> frombits): + return None + acc = ((acc << frombits) | value) & max_acc + bits += frombits + while bits >= tobits: + bits -= tobits + ret.append((acc >> bits) & maxv) + if pad: + if bits: + ret.append((acc << (tobits - bits)) & maxv) + elif bits >= frombits or ((acc << (tobits - bits)) & maxv): + return None + return ret + + +def decode(hrp, addr): + """Decode a segwit address.""" + hrpgot, data, spec = bech32_decode(addr) + if hrpgot != hrp: + return (None, None) + decoded = convertbits(data[1:], 5, 8, False) + if decoded is None or len(decoded) < 2 or len(decoded) > 40: + return (None, None) + if data[0] > 16: + return (None, None) + if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: + return (None, None) + if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M: + return (None, None) + return (data[0], decoded) + + +def encode(hrp, witver, witprog): + """Encode a segwit address.""" + spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M + ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec) + if decode(hrp, ret) == (None, None): + return None + return ret + diff --git a/base/dependencies/validate_url.py b/base/dependencies/validate_url.py new file mode 100755 index 0000000..3e46684 --- /dev/null +++ b/base/dependencies/validate_url.py @@ -0,0 +1,70 @@ +import socket +from typing import Union +from urllib.parse import urlparse +from ipaddress import ip_address, ip_network, IPv4Address + +class UrlValidator: + @staticmethod + def is_internal_address(ip: Union[IPv4Address]) -> bool: + return any([ + ip.is_private, + ip.is_unspecified, + ip.is_reserved, + ip.is_loopback, + ip.is_multicast, + ip.is_link_local, + ]) + + @classmethod + def validate(cls, url: str): + DEFAULT_PORT_WHITELIST = {80, 81, 8080, 443, 8443, 8000} + DEFAULT_SCHEME_WHITELIST = {'http', 'https'} + DEFAULT_HOST_BLACKLIST = {'192.0.0.192', '169.254.169.254', '100.100.100.200', 'metadata.packet.net', 'metadata.google.internal'} + DEFAULT_CHARACTER_WHITELIST = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:/-_.?&=' + + if url is None: + return False + + whitelist_set = set(DEFAULT_CHARACTER_WHITELIST) + if any(c not in whitelist_set for c in url): + return False + + try: + ip = ip_address(url) + except ValueError: + try: + host = urlparse(url).hostname + ip = ip_address(str(socket.gethostbyname(host))) + except: + return False + + port_whitelist = DEFAULT_PORT_WHITELIST.copy() + scheme_whitelist = DEFAULT_SCHEME_WHITELIST.copy() + host_blacklist = DEFAULT_HOST_BLACKLIST.copy() + + try: + port, scheme = urlparse(url).port, urlparse(url).scheme + except: + return False + + if scheme_whitelist and scheme is not None and scheme not in scheme_whitelist: + return False + + if host_blacklist and host is not None and host in host_blacklist: + return False + + if port_whitelist and port is not None and port not in port_whitelist: + return False + + if ip.version == 4: + if not ip.is_private: + # CGNAT IPs do not set `is_private` so `not is_global` added + if not ip_network(ip).is_global: + return False + else: + return False + + if cls.is_internal_address(ip): + return False + + return True \ No newline at end of file diff --git a/base/forms.py b/base/forms.py old mode 100644 new mode 100755 index 9a45957..19036ba --- a/base/forms.py +++ b/base/forms.py @@ -1,5 +1,18 @@ +from django import forms from django.forms import ModelForm -from .models import VendorsData, VendorsAddresses +from users.models import User +from .models import VendorsData, VendorsAddresses, InvoiceCreation, ApiPaymentCreation +from django.contrib.auth.forms import SetPasswordForm, PasswordResetForm + +class InvoiceCreationForm(ModelForm): + class Meta: + model = InvoiceCreation + fields = ['invoiceID', 'invoiceAmount', 'invoiceCoin', 'invoiceCallbackLink', 'invoiceReturnLink', 'invoiceCoin'] + +class ApiPaymentCreationForm(ModelForm): + class Meta: + model = ApiPaymentCreation + fields = ['userUUID', 'usercallbackUrl','userIP','userCoin','statusFlag','paidFlag','ourAddr'] class VendorEditForm(ModelForm): class Meta: @@ -9,4 +22,41 @@ class VendorEditForm(ModelForm): class VendorAddrAddForm(ModelForm): class Meta: model = VendorsAddresses - fields = ['coin', 'address'] \ No newline at end of file + fields = ['coin', 'address'] + +class UserRegistrationForm(ModelForm): + MIN_LENGTH = 8 + class Meta: + model = User + fields = ['first_name', 'last_name', 'email', 'password'] + + def clean_email(self): + email = self.cleaned_data.get('email') + if User.objects.filter(email=email).exists(): + raise forms.ValidationError('Email used, try reseting the password if thats you.') + return email + + def clean(self): + cleaned_data = super().clean() + password = cleaned_data.get('password') + if len(password) < self.MIN_LENGTH: + raise forms.ValidationError('The password you are trying to use is too short') + + +class SetPasswordForm(SetPasswordForm): + class Meta: + model = User() + fields = ['new_password1', 'new_password2'] + + def clean(self): + cleaned_data = super().clean() + password = cleaned_data.get('new_password1') + password2 = cleaned_data.get('new_password2') + +class PasswordResetForm(PasswordResetForm): + class Meta: + model = User() + fields = ['email'] + + def __init__(self, *args, **kwargs): + super(PasswordResetForm, self).__init__(*args, **kwargs) \ No newline at end of file diff --git a/base/functions.py b/base/functions.py old mode 100644 new mode 100755 index ef5b68a..f5da62a --- a/base/functions.py +++ b/base/functions.py @@ -1,14 +1,78 @@ -import string, hashlib, binascii, random, socket, base58, sys +import string, hashlib, binascii, random, socket, base58, sys, requests, json +from requests.auth import HTTPDigestAuth from typing import Union from urllib.parse import urlparse from ipaddress import ip_address, ip_network, IPv4Address from base58 import b58decode_check, b58encode_check from enum import Enum + +class RPCHost(object): + def __init__(self, url): + self._session = requests.Session() + self._url = url + self._headers = {'content-type': 'application/json'} + def call(self, rpcMethod, *params): + payload = json.dumps({"method": rpcMethod, "params": list(params), "jsonrpc": "2.0"}) + tries = 3 + hadConnectionFailures = False + while True: + try: + response = self._session.post(self._url, headers=self._headers, data=payload, timeout=15) + except requests.exceptions.ConnectionError: + tries -= 1 + if tries == 0: + raise Exception('Failed to connect for remote procedure call.') + hadFailedConnections = True + print("Couldn't connect for remote procedure call, will sleep for two seconds and then try again ({} more tries)".format(tries)) + #time.sleep(2) + else: + if hadConnectionFailures: + print('Connected for remote procedure call after retry.') + break + if not response.status_code in (200, 500): + raise Exception('RPC connection failure: ' + str(response.status_code) + ' ' + response.reason) + responseJSON = response.json() + if 'error' in responseJSON and responseJSON['error'] != None: + raise Exception('Error in RPC call: ' + str(responseJSON['error'])) + return responseJSON['result'] + +class RPCXMR(object): + def __init__(self, url, user, password): + self._session = requests.Session() + self._url = url + self._user = user + self._pass = password + self._headers = {} + + def call(self, rpcMethod, params): + payload = json.dumps({"method": rpcMethod, "params": params, "jsonrpc": "2.0"}) + tries = 3 + hadConnectionFailures = False + while True: + try: + response = self._session.post(self._url, headers=self._headers, data=payload, auth=HTTPDigestAuth(self._user, self._pass), timeout=15) + except requests.exceptions.ConnectionError: + tries -= 1 + if tries == 0: + raise Exception('Failed to connect for remote procedure call.') + hadFailedConnections = True + print("Couldn't connect for remote procedure call, will sleep for two seconds and then try again ({} more tries)".format(tries)) + #time.sleep(2) + else: + if hadConnectionFailures: + print('Connected for remote procedure call after retry.') + break + if not response.status_code in (200, 500): + raise Exception('RPC connection failure: ' + str(response.status_code) + ' ' + response.reason) + responseJSON = response.json() + if 'error' in responseJSON and responseJSON['error'] != None: + raise Exception('Error in RPC call: ' + str(responseJSON['error'])) + return responseJSON['result'] + def vendor_generator(size=6, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) - def decodeBase58(address): decoded = base58.b58decode(address).hex() prefixAndHash = decoded[:len(decoded)-8] @@ -38,15 +102,17 @@ def decodeMonero(address): def checksumCheck(method, address): match method.lower(): case 'btc': - return decodeBase58(address) if address[0] == '1' or address[0] == '3' else True if address[0:3] == 'bc1' and decode("bc", address)[0] != None else False + return decodeBase58(address) if address[0] == '1' or address[0] == '3' else True if address[0:3] == 'bc1' and bdecode("bc", address)[0] != None else False case 'btct': - return decodeBase58(address) if address[0] == '2' else True if address[0:3] == 'tb1' and decode("tb", address)[0] != None else False + return decodeBase58(address) if address[0] == '2' else True if address[0:3] == 'tb1' and bdecode("tb", address)[0] != None else False case 'ltc': - return decodeBase58(address) if address[0] == '3' or address[0] == 'M' or address[0] == 'L' else True if address[0:4] == 'ltc1' and decode("ltc", address)[0] != None else False + return decodeBase58(address) if address[0] == '3' or address[0] == 'M' or address[0] == 'L' else True if address[0:4] == 'ltc1' and bdecode("ltc", address)[0] != None else False case 'bch': return is_valid(address) if address[0] == '1' else True if is_valid('bitcoincash:'+address) == True else False case 'zec': return decodeBase58(address) if address[0] == 't' or address[0] == 'z' else False + case 'doge': + return decodeBase58(address) case 'xmr': #needs new function to check if address is valid, a decoder maybe return decodeMonero(address) @@ -217,7 +283,7 @@ def convertbits(data, frombits, tobits, pad=True): return ret -def decode(hrp, addr): +def bdecode(hrp, addr): """Decode a segwit address.""" hrpgot, data, spec = bech32_decode(addr) if hrpgot != hrp: @@ -234,11 +300,11 @@ def decode(hrp, addr): return (data[0], decoded) -def encode(hrp, witver, witprog): +def bencode(hrp, witver, witprog): """Encode a segwit address.""" spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec) - if decode(hrp, ret) == (None, None): + if bdecode(hrp, ret) == (None, None): return None return ret @@ -626,4 +692,4 @@ def decode(enc): return _binToHex(data) ######################################################################### -######################################################################### \ No newline at end of file +######################################################################### diff --git a/base/migrations/0001_initial.py b/base/migrations/0001_initial.py old mode 100644 new mode 100755 diff --git a/base/migrations/0002_initial.py b/base/migrations/0002_initial.py old mode 100644 new mode 100755 diff --git a/base/migrations/0003_alter_vendorsdata_options.py b/base/migrations/0003_alter_vendorsdata_options.py old mode 100644 new mode 100755 diff --git a/base/migrations/0004_vendorsdata_vendoruuid.py b/base/migrations/0004_vendorsdata_vendoruuid.py old mode 100644 new mode 100755 diff --git a/base/migrations/0005_alter_vendorsdata_vendorisactive.py b/base/migrations/0005_alter_vendorsdata_vendorisactive.py old mode 100644 new mode 100755 diff --git a/base/migrations/0006_alter_vendorsdata_vendordeleted_and_more.py b/base/migrations/0006_alter_vendorsdata_vendordeleted_and_more.py old mode 100644 new mode 100755 diff --git a/base/migrations/0007_vendorsdata_vendorupdated_and_more.py b/base/migrations/0007_vendorsdata_vendorupdated_and_more.py old mode 100644 new mode 100755 diff --git a/base/migrations/0008_alter_vendorsdata_vendorwebaddr.py b/base/migrations/0008_alter_vendorsdata_vendorwebaddr.py old mode 100644 new mode 100755 diff --git a/base/migrations/0009_alter_vendorsdata_id.py b/base/migrations/0009_alter_vendorsdata_id.py old mode 100644 new mode 100755 diff --git a/base/migrations/0010_cryptocoins.py b/base/migrations/0010_cryptocoins.py new file mode 100755 index 0000000..04789a3 --- /dev/null +++ b/base/migrations/0010_cryptocoins.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2 on 2023-05-17 10:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0009_alter_vendorsdata_id'), + ] + + operations = [ + migrations.CreateModel( + name='CryptoCoins', + fields=[ + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('coinName', models.CharField(max_length=250)), + ('coinSymbol', models.CharField(max_length=10)), + ('coinIsActive', models.BooleanField(default=True)), + ('coinAddDate', models.DateTimeField(auto_now_add=True)), + ('coinUpdated', models.DateTimeField(auto_now=True)), + ('coinDelete', models.DateTimeField(auto_now_add=True)), + ('coinDeleted', models.BooleanField(default=False)), + ], + options={ + 'verbose_name': 'Crypto Coin', + 'verbose_name_plural': 'Crypto Coins', + 'ordering': ['-id'], + }, + ), + ] diff --git a/base/migrations/0011_alter_cryptocoins_coindelete_vendorsaddresses.py b/base/migrations/0011_alter_cryptocoins_coindelete_vendorsaddresses.py new file mode 100755 index 0000000..90c3723 --- /dev/null +++ b/base/migrations/0011_alter_cryptocoins_coindelete_vendorsaddresses.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2 on 2023-05-17 11:25 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0010_cryptocoins'), + ] + + operations = [ + migrations.AlterField( + model_name='cryptocoins', + name='coinDelete', + field=models.DateTimeField(blank=True), + ), + migrations.CreateModel( + name='VendorsAddresses', + fields=[ + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('vendorUUID', models.UUIDField()), + ('address', models.CharField(max_length=250)), + ('addrAddDate', models.DateTimeField(auto_now_add=True)), + ('addrDeleted', models.BooleanField(default=False)), + ('addrUpdated', models.DateTimeField(auto_now=True)), + ('addrIsActive', models.BooleanField(default=True)), + ('Coin', models.ManyToManyField(to='base.cryptocoins')), + ('vendor', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='base.vendorsdata')), + ], + options={ + 'verbose_name': 'Vendor', + 'verbose_name_plural': 'Vendors', + 'ordering': ['-id'], + }, + ), + ] diff --git a/base/migrations/0012_alter_vendorsaddresses_options.py b/base/migrations/0012_alter_vendorsaddresses_options.py new file mode 100755 index 0000000..73e2054 --- /dev/null +++ b/base/migrations/0012_alter_vendorsaddresses_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-05-17 11:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0011_alter_cryptocoins_coindelete_vendorsaddresses'), + ] + + operations = [ + migrations.AlterModelOptions( + name='vendorsaddresses', + options={'ordering': ['-id'], 'verbose_name': 'Address', 'verbose_name_plural': 'Addresses'}, + ), + ] diff --git a/base/migrations/0013_remove_vendorsaddresses_coin_vendorsaddresses_coin.py b/base/migrations/0013_remove_vendorsaddresses_coin_vendorsaddresses_coin.py new file mode 100755 index 0000000..6f1a0aa --- /dev/null +++ b/base/migrations/0013_remove_vendorsaddresses_coin_vendorsaddresses_coin.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2 on 2023-05-17 11:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0012_alter_vendorsaddresses_options'), + ] + + operations = [ + migrations.RemoveField( + model_name='vendorsaddresses', + name='Coin', + ), + migrations.AddField( + model_name='vendorsaddresses', + name='Coin', + field=models.IntegerField(default=0), + ), + ] diff --git a/base/migrations/0014_alter_cryptocoins_coindelete.py b/base/migrations/0014_alter_cryptocoins_coindelete.py new file mode 100755 index 0000000..5dddbd5 --- /dev/null +++ b/base/migrations/0014_alter_cryptocoins_coindelete.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-05-17 11:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0013_remove_vendorsaddresses_coin_vendorsaddresses_coin'), + ] + + operations = [ + migrations.AlterField( + model_name='cryptocoins', + name='coinDelete', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/base/migrations/0015_alter_cryptocoins_coindelete.py b/base/migrations/0015_alter_cryptocoins_coindelete.py new file mode 100755 index 0000000..dd997e0 --- /dev/null +++ b/base/migrations/0015_alter_cryptocoins_coindelete.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-05-18 09:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0014_alter_cryptocoins_coindelete'), + ] + + operations = [ + migrations.AlterField( + model_name='cryptocoins', + name='coinDelete', + field=models.DateTimeField(auto_now_add=True, null=True), + ), + ] diff --git a/base/migrations/0016_rename_coin_vendorsaddresses_coin_and_more.py b/base/migrations/0016_rename_coin_vendorsaddresses_coin_and_more.py new file mode 100755 index 0000000..5b15208 --- /dev/null +++ b/base/migrations/0016_rename_coin_vendorsaddresses_coin_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2 on 2023-05-18 12:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0015_alter_cryptocoins_coindelete'), + ] + + operations = [ + migrations.RenameField( + model_name='vendorsaddresses', + old_name='Coin', + new_name='coin', + ), + migrations.AlterField( + model_name='vendorsdata', + name='vendorSecretKey', + field=models.CharField(max_length=250), + ), + ] diff --git a/base/migrations/0017_alter_vendorsaddresses_options_and_more.py b/base/migrations/0017_alter_vendorsaddresses_options_and_more.py new file mode 100755 index 0000000..e4f9519 --- /dev/null +++ b/base/migrations/0017_alter_vendorsaddresses_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2 on 2023-05-19 12:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0016_rename_coin_vendorsaddresses_coin_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='vendorsaddresses', + options={'ordering': ['id'], 'verbose_name': 'Address', 'verbose_name_plural': 'Addresses'}, + ), + migrations.AlterField( + model_name='vendorsaddresses', + name='coin', + field=models.CharField(max_length=10), + ), + ] diff --git a/base/migrations/0018_alter_vendorsaddresses_options_and_more.py b/base/migrations/0018_alter_vendorsaddresses_options_and_more.py new file mode 100755 index 0000000..db52968 --- /dev/null +++ b/base/migrations/0018_alter_vendorsaddresses_options_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2 on 2023-05-21 10:19 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0017_alter_vendorsaddresses_options_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='vendorsaddresses', + options={'ordering': ['-addrIsActive'], 'verbose_name': 'Address', 'verbose_name_plural': 'Addresses'}, + ), + migrations.AddField( + model_name='vendorsaddresses', + name='vendorid', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/base/migrations/0019_alter_vendorsaddresses_vendorid.py b/base/migrations/0019_alter_vendorsaddresses_vendorid.py new file mode 100755 index 0000000..c7acaab --- /dev/null +++ b/base/migrations/0019_alter_vendorsaddresses_vendorid.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2 on 2023-05-21 10:20 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0018_alter_vendorsaddresses_options_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='vendorsaddresses', + name='vendorid', + field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/base/migrations/0020_alter_vendorsaddresses_vendorid.py b/base/migrations/0020_alter_vendorsaddresses_vendorid.py new file mode 100755 index 0000000..93e165e --- /dev/null +++ b/base/migrations/0020_alter_vendorsaddresses_vendorid.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2 on 2023-05-21 10:21 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0019_alter_vendorsaddresses_vendorid'), + ] + + operations = [ + migrations.AlterField( + model_name='vendorsaddresses', + name='vendorid', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/base/migrations/0021_alter_vendorsaddresses_vendorid.py b/base/migrations/0021_alter_vendorsaddresses_vendorid.py new file mode 100755 index 0000000..9a07c43 --- /dev/null +++ b/base/migrations/0021_alter_vendorsaddresses_vendorid.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2 on 2023-05-21 10:22 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0020_alter_vendorsaddresses_vendorid'), + ] + + operations = [ + migrations.AlterField( + model_name='vendorsaddresses', + name='vendorid', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/base/migrations/0022_alter_vendorsaddresses_options_and_more.py b/base/migrations/0022_alter_vendorsaddresses_options_and_more.py new file mode 100755 index 0000000..a1ec9c5 --- /dev/null +++ b/base/migrations/0022_alter_vendorsaddresses_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2 on 2023-05-29 11:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0021_alter_vendorsaddresses_vendorid'), + ] + + operations = [ + migrations.AlterModelOptions( + name='vendorsaddresses', + options={'ordering': ['-addrAddDate'], 'verbose_name': 'Address', 'verbose_name_plural': 'Addresses'}, + ), + migrations.AddField( + model_name='vendorsdata', + name='vendorNetworkFee', + field=models.IntegerField(default=0), + ), + ] diff --git a/base/migrations/0023_invoicecreation.py b/base/migrations/0023_invoicecreation.py new file mode 100755 index 0000000..2fbd99e --- /dev/null +++ b/base/migrations/0023_invoicecreation.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2 on 2023-07-06 08:37 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('base', '0022_alter_vendorsaddresses_options_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='InvoiceCreation', + fields=[ + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('invoiceUUID', models.UUIDField()), + ('invoiceID', models.CharField(max_length=255)), + ('invoiceAmount', models.DecimalField(decimal_places=2, max_digits=20)), + ('invoiceCoin', models.CharField(max_length=10)), + ('invoiceState', models.IntegerField(default=0)), + ('invoiceBuyerEmail', models.CharField(max_length=255)), + ('invoiceCallbackLink', models.CharField(max_length=1000)), + ('invoiceReturnLink', models.CharField(max_length=1000)), + ('invoiceDeleteLink', models.CharField(max_length=1000)), + ('invoiceDeleted', models.BooleanField(default=False)), + ('invoiceAddDate', models.DateTimeField(auto_now_add=True)), + ('invoiceUpdateDate', models.DateTimeField(auto_now=True)), + ('invoiceDeleteDate', models.DateTimeField(blank=True, null=True)), + ('invoiceVendor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.vendorsdata')), + ('invoiceVendorid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Invoice', + 'verbose_name_plural': 'Invoices', + 'ordering': ['-invoiceAddDate'], + }, + ), + ] diff --git a/base/migrations/0024_alter_invoicecreation_invoicebuyeremail.py b/base/migrations/0024_alter_invoicecreation_invoicebuyeremail.py new file mode 100755 index 0000000..5e096aa --- /dev/null +++ b/base/migrations/0024_alter_invoicecreation_invoicebuyeremail.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-07-07 13:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0023_invoicecreation'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceBuyerEmail', + field=models.CharField(max_length=255, null=True), + ), + ] diff --git a/base/migrations/0025_alter_invoicecreation_invoicecoin.py b/base/migrations/0025_alter_invoicecreation_invoicecoin.py new file mode 100755 index 0000000..678f3de --- /dev/null +++ b/base/migrations/0025_alter_invoicecreation_invoicecoin.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-07-07 13:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0024_alter_invoicecreation_invoicebuyeremail'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceCoin', + field=models.CharField(default='USD', max_length=10), + ), + ] diff --git a/base/migrations/0026_alter_invoicecreation_invoicecallbacklink_and_more.py b/base/migrations/0026_alter_invoicecreation_invoicecallbacklink_and_more.py new file mode 100755 index 0000000..ebf7138 --- /dev/null +++ b/base/migrations/0026_alter_invoicecreation_invoicecallbacklink_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2 on 2023-07-07 14:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0025_alter_invoicecreation_invoicecoin'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceCallbackLink', + field=models.URLField(max_length=1000), + ), + migrations.AlterField( + model_name='invoicecreation', + name='invoiceDeleteLink', + field=models.URLField(max_length=1000), + ), + migrations.AlterField( + model_name='invoicecreation', + name='invoiceReturnLink', + field=models.URLField(max_length=1000), + ), + ] diff --git a/base/migrations/0027_alter_invoicecreation_invoicebuyeremail.py b/base/migrations/0027_alter_invoicecreation_invoicebuyeremail.py new file mode 100755 index 0000000..9b004e5 --- /dev/null +++ b/base/migrations/0027_alter_invoicecreation_invoicebuyeremail.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-07-07 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0026_alter_invoicecreation_invoicecallbacklink_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceBuyerEmail', + field=models.EmailField(max_length=255, null=True), + ), + ] diff --git a/base/migrations/0028_alter_invoicecreation_invoicecoin.py b/base/migrations/0028_alter_invoicecreation_invoicecoin.py new file mode 100755 index 0000000..6e54d31 --- /dev/null +++ b/base/migrations/0028_alter_invoicecreation_invoicecoin.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2 on 2023-07-08 11:35 + +import base.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0027_alter_invoicecreation_invoicebuyeremail'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceCoin', + field=models.CharField(default=base.models.InvoiceCreation.default_currency, max_length=10), + ), + ] diff --git a/base/migrations/0029_alter_invoicecreation_invoicedeletelink.py b/base/migrations/0029_alter_invoicecreation_invoicedeletelink.py new file mode 100755 index 0000000..49a6057 --- /dev/null +++ b/base/migrations/0029_alter_invoicecreation_invoicedeletelink.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-07-08 11:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0028_alter_invoicecreation_invoicecoin'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceDeleteLink', + field=models.URLField(max_length=1000, null=True), + ), + ] diff --git a/base/migrations/0030_alter_invoicecreation_invoiceuuid.py b/base/migrations/0030_alter_invoicecreation_invoiceuuid.py new file mode 100755 index 0000000..37ee36f --- /dev/null +++ b/base/migrations/0030_alter_invoicecreation_invoiceuuid.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2 on 2023-07-08 12:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0029_alter_invoicecreation_invoicedeletelink'), + ] + + operations = [ + migrations.AlterField( + model_name='invoicecreation', + name='invoiceUUID', + field=models.UUIDField(unique=True), + ), + ] diff --git a/base/migrations/0031_apipaymentcreation_cryptocoins_coinapi_and_more.py b/base/migrations/0031_apipaymentcreation_cryptocoins_coinapi_and_more.py new file mode 100755 index 0000000..f017c99 --- /dev/null +++ b/base/migrations/0031_apipaymentcreation_cryptocoins_coinapi_and_more.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2 on 2023-08-08 09:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0030_alter_invoicecreation_invoiceuuid'), + ] + + operations = [ + migrations.CreateModel( + name='ApiPaymentCreation', + fields=[ + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('userAddr', models.CharField(max_length=255)), + ('userUUID', models.UUIDField()), + ('userCoin', models.CharField(max_length=10)), + ('userAmount', models.DecimalField(decimal_places=2, max_digits=20)), + ('usercallbackUrl', models.URLField(max_length=1000, null=True)), + ('userIP', models.GenericIPAddressField()), + ('ourAddr', models.CharField(max_length=255)), + ('statusFlag', models.IntegerField(default=0)), + ('paidFlag', models.IntegerField(default=0)), + ('created', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'verbose_name': 'ApiInvoice', + 'verbose_name_plural': 'ApiInvoices', + 'ordering': ['-id'], + }, + ), + migrations.AddField( + model_name='cryptocoins', + name='coinAPI', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='cryptocoins', + name='coinMerch', + field=models.BooleanField(default=True), + ), + ] diff --git a/base/migrations/__init__.py b/base/migrations/__init__.py old mode 100644 new mode 100755 diff --git a/base/models.py b/base/models.py old mode 100644 new mode 100755 index e8106a7..59bec2a --- a/base/models.py +++ b/base/models.py @@ -9,6 +9,8 @@ class CryptoCoins(models.Model): id = models.BigAutoField(primary_key=True) coinName = models.CharField(max_length=250) coinSymbol = models.CharField(max_length=10) + coinAPI = models.BooleanField(default=True) + coinMerch = models.BooleanField(default=True) coinIsActive = models.BooleanField(default=True) coinAddDate = models.DateTimeField(auto_now_add=True) coinUpdated = models.DateTimeField(auto_now=True) @@ -64,6 +66,9 @@ class VendorsAddresses(models.Model): def __str__(self): return self.address + + def __repr__(self): + return self._repr() class Meta: verbose_name = "Address" @@ -71,4 +76,57 @@ class VendorsAddresses(models.Model): ordering = ["-addrAddDate"] +class InvoiceCreation(models.Model): + def default_currency(): + return 'USD' + + id = models.BigAutoField(primary_key=True) + invoiceVendor = models.ForeignKey(VendorsData, on_delete=models.CASCADE) + invoiceVendorid = models.ForeignKey(User, on_delete=models.CASCADE) + invoiceUUID = models.UUIDField(unique=True) + invoiceID = models.CharField(max_length=255) + invoiceAmount = models.DecimalField(max_digits=20, decimal_places=2) + invoiceCoin = models.CharField(max_length=10, default=default_currency, null=False) + invoiceState = models.IntegerField(default=0) + invoiceBuyerEmail = models.EmailField(max_length=255, null=True) + invoiceCallbackLink = models.URLField(max_length=1000) + invoiceReturnLink = models.URLField(max_length=1000) + invoiceDeleteLink = models.URLField(max_length=1000, null=True) + invoiceDeleted = models.BooleanField(default=False) + invoiceAddDate = models.DateTimeField(auto_now_add=True) + invoiceUpdateDate = models.DateTimeField(auto_now=True) + invoiceDeleteDate = models.DateTimeField(blank=True, null=True) + + def __str__(self): + return str(self.invoiceUUID) + + def __repr__(self): + return self._repr() + + class Meta: + verbose_name = "Invoice" + verbose_name_plural = "Invoices" + ordering = ["-invoiceAddDate"] + + +class ApiPaymentCreation(models.Model): + id = models.BigAutoField(primary_key=True) + userAddr = models.CharField(max_length=255) + userUUID = models.UUIDField() + userCoin = models.CharField(max_length=10) + userAmount = models.DecimalField(max_digits=20, decimal_places=2) + usercallbackUrl = models.URLField(max_length=1000, null=True) + userIP = models.GenericIPAddressField() + ourAddr = models.CharField(max_length=255) + statusFlag = models.IntegerField(default=0) + paidFlag = models.IntegerField(default=0) + created = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return str(self.ourAddr) + + class Meta: + verbose_name = "ApiInvoice" + verbose_name_plural = "ApiInvoices" + ordering = ["-id"] \ No newline at end of file diff --git a/base/rpcs.py b/base/rpcs.py new file mode 100755 index 0000000..5d2a9b8 --- /dev/null +++ b/base/rpcs.py @@ -0,0 +1,47 @@ +## DAEMONS ## +# BTC +rpcs = { + 'BTC': { + 'host': '172.16.0.2', + 'port': 8332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'BTCT': { + 'host': '172.16.2.2', + 'port': 18332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'LTC': { + 'host': '172.16.1.2', + 'port': 9332, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'BCH': { + 'host': '172.16.3.2', + 'port': 8552, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'ZEC': { + 'host': '172.16.5.2', + 'port': 8552, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'DOGE': { + 'host': '172.16.6.2', + 'port': 25555, + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, + 'XMR': { + 'host': 'http://172.16.4.3:18083/json_rpc', + 'user': '55c44311a1e1708ec1afbf9949c96d08', + 'pass': 'lzD8NH4sexdTHnRJ1BxZfBvUxZHlvmW2bwDsF' + }, +} + +API_FEE = 0.02 \ No newline at end of file diff --git a/base/.DS_Store b/base/templates/base/._inv.html old mode 100644 new mode 100755 similarity index 60% rename from base/.DS_Store rename to base/templates/base/._inv.html index 10b5eaa..12cb04d Binary files a/base/.DS_Store and b/base/templates/base/._inv.html differ diff --git a/templates/.DS_Store b/base/templates/base/._lp_invoice.html old mode 100644 new mode 100755 similarity index 60% rename from templates/.DS_Store rename to base/templates/base/._lp_invoice.html index 2b11b97..bfa835a Binary files a/templates/.DS_Store and b/base/templates/base/._lp_invoice.html differ diff --git a/base/templates/base/inv.html b/base/templates/base/inv.html new file mode 100755 index 0000000..269e2ef --- /dev/null +++ b/base/templates/base/inv.html @@ -0,0 +1,20 @@ + + +
+ + +BTC
+Don't have an account? Sign up
-Sold by {{vendor.vendorWebName}}
+Feedback: ★★★★★ 100%
+Sold by {{vendor.vendorWebName}}
+Feedback: ★★★★★ 100%
++ Login or register to start :-) +
++ Login or register to start :-) +
++ Login or register to start :-) +
++ Login or register to start :-) +
+`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: var(--#{$prefix}link-color);\n text-decoration: $link-decoration;\n\n &:hover {\n color: var(--#{$prefix}link-hover-color);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `