up2date #2

Merged
mike merged 1 commits from feature/vendor into main 2023-12-05 14:51:39 +00:00
2035 changed files with 5550 additions and 126 deletions

3
.gitignore vendored Normal file → Executable file
View File

@ -3,3 +3,6 @@
.DS_Store
__pycache__
db.sqlite3
._.DS_Store
._src
env

0
base/__init__.py Normal file → Executable file
View File

0
base/admin.py Normal file → Executable file
View File

0
base/apps.py Normal file → Executable file
View File

0
base/dependencies/__init__.py Executable file
View File

129
base/dependencies/bchconvert.py Executable file
View File

@ -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

70
base/dependencies/crypto.py Executable file
View File

@ -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

185
base/dependencies/moneropy.py Executable file
View File

@ -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)

View File

@ -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

139
base/dependencies/segwit_addr.py Executable file
View File

@ -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

View File

@ -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

52
base/forms.py Normal file → Executable file
View File

@ -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:
@ -10,3 +23,40 @@ class VendorAddrAddForm(ModelForm):
class Meta:
model = VendorsAddresses
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)

82
base/functions.py Normal file → Executable file
View File

@ -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

0
base/migrations/0001_initial.py Normal file → Executable file
View File

0
base/migrations/0002_initial.py Normal file → Executable file
View File

0
base/migrations/0003_alter_vendorsdata_options.py Normal file → Executable file
View File

0
base/migrations/0004_vendorsdata_vendoruuid.py Normal file → Executable file
View File

View File

View File

View File

View File

0
base/migrations/0009_alter_vendorsdata_id.py Normal file → Executable file
View File

View File

@ -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'],
},
),
]

View File

@ -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'],
},
),
]

View File

@ -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'},
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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'],
},
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

0
base/migrations/__init__.py Normal file → Executable file
View File

58
base/models.py Normal file → Executable file
View File

@ -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)
@ -65,10 +67,66 @@ class VendorsAddresses(models.Model):
def __str__(self):
return self.address
def __repr__(self):
return self._repr()
class Meta:
verbose_name = "Address"
verbose_name_plural = "Addresses"
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"]

47
base/rpcs.py Executable file
View File

@ -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

BIN
base/.DS_Store → base/templates/base/._inv.html Normal file → Executable file

Binary file not shown.

Binary file not shown.

20
base/templates/base/inv.html Executable file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Square with Bitcoin Image and Text</title>
</head>
<body>
<div class="outer-square">
<div class="inner-square">
<img class="image" src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/46/Bitcoin.svg/800px-Bitcoin.svg.png" alt="Bitcoin Logo" width="50" height="50">
<div class="crypto-info">
<h1>Bitcoin</h1>
<p>BTC</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,83 +0,0 @@
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title> </title>
<meta name="robots" content="index">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="LitePay.ch">
<!-- Favicon icon -->
<link rel="icon" type="image/png" sizes="16x16" href="https://ik.imagekit.io/litepaych/assets/dashboard/images/logo_litepay_2020_white_box.png">
<link href="https://litepay.ch//assets/new/secure/css/style.css" rel="stylesheet">
<link rel="canonical" href="https://litepay.ch/merchant/login">
</head>
{% block content %}
<!-- ============================================================== -->
<!-- Start right Content here -->
<!-- ============================================================== -->
<!-- Main content -->
<link rel="icon" type="image/png" sizes="16x16" href="https://ik.imagekit.io/litepaych/assets/dashboard/images/logo_litepay_2020_white_box.png">
<h1 style="visibility: hidden"> Sign in your Litepay.ch account </h1>
<body class="h-100">
<div class="authincation h-100">
<div class="container h-100">
<div class="row justify-content-center h-100 align-items-center">
<div class="col-md-6">
<div class="authincation-content">
<div class="row no-gutters">
<div class="col-xl-12">
<div class="auth-form">
<img style="display: block; margin-left: auto; margin-right: auto; width: 50%; padding-bottom: 2px" src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" alt="Litepay.ch Merchant"></a>
<h2 class="text-center mb-4">Sign in</h2>
<form action="" method="POST">
{% csrf_token %}
<div class="form-group">
<label class="mb-1"><strong>Email</strong></label>
<input type="email" class="form-control" name="email" value="Email">
</div>
<div class="form-group">
<label class="mb-1"><strong>Password</strong></label>
<input type="password" class="form-control" name="password" value="Password">
</div>
<div class="form-row d-flex justify-content-between mt-4 mb-2">
<div class="form-group">
</div>
<div class="form-group">
<a href="/merchant/forgot-password">Forgot Password?</a>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-block">Sign Me In</button>
</div>
</form>
<div class="new-account mt-3">
<p>Don't have an account? <a class="text-primary" href="/merchant/register">Sign up</a></p>
</div>
</div>
{% if messages %}
<ul class="messages text-center">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<!-- end main content-->
{% endblock content %}
</html>

View File

@ -0,0 +1,136 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>Satoshi - DeFi and Crypto Exchange Theme</title>
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
</head>
<body class="bg-surface-secondary">
<div class="d-flex flex-column flex-lg-row h-lg-full">
<div class="flex-lg-fill overflow-x-auto vstack h-lg-screen">
<div class="flex-fill overflow-y-lg-auto scrollbar bg-surface-primary rounded-top-4 rounded-top-start-lg-4 rounded-top-end-lg-0 border-top border-lg shadow">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<div class="modal fade show" id="cryptoModal" tabindex="-1" aria-labelledby="cryptoModalLabel" style="display: block" aria-modal="true" role="dialog">
<div class="modal-dialog modal-dialog-centered">
<div class="row g-3 g-xxl-6">
<div class="col-xxl-12">
<div class="vstack gap-3 gap-md-6">
<div class="row g-3">
<div class="col-md col-sm-6">
<div class="card bg-success bg-opacity-10 border-success border-opacity-40">
<div class="card-body p-4">
<div class="d-flex align-items-center gap-2">
<img class="w-5 flex-none" src="{% static '/img/crypto/color/usdt.svg' %}" alt="..." />
<h6>USDT</h6>
</div>
<div class="text-xs mt-4">
Total balance
</div>
<div class="text-sm font-semibold">
75.800,00 USDT
</div>
</div>
</div>
</div>
<div class="col-md col-sm-6">
<div class="card border-primary-hover">
<div class="card-body p-4">
<div class="d-flex align-items-center gap-2">
<img class="w-5 flex-none" src="{% static '/img/crypto/color/btc.svg' %}" alt="..." />
<a href="/pages/exchange-details.html" class="h6 stretched-link">BTC</a>
</div>
<div class="text-sm font-semibold mt-3">
3.2893 USDT
</div>
<div class="d-flex align-items-center gap-2 mt-1 text-xs">
<span class="badge badge-xs rounded-pill text-bg-success">
<i class="bi bi-arrow-up-right"></i>
</span>
<span>+13.7%</span>
</div>
</div>
</div>
</div>
<div class="col-md col-sm-6">
<div class="card border-primary-hover">
<div class="card-body p-4">
<div class="d-flex align-items-center gap-2">
<img class="w-5 flex-none" src="{% static '/img/crypto/color/ada.svg' %}" alt="..." />
<a href="/pages/exchange-details.html" class="h6 stretched-link">ADA</a>
</div>
<div class="text-sm font-semibold mt-3">
10.745,49 ADA
</div>
<div class="d-flex align-items-center gap-2 mt-1 text-xs">
<span class="badge badge-xs rounded-pill text-bg-danger">
<i class="bi bi-arrow-up-right"></i>
</span>
<span>-3.2%</span>
</div>
</div>
</div>
</div>
<div class="col-md col-sm-6">
<div class="card border-primary-hover">
<div class="card-body p-4">
<div class="d-flex align-items-center gap-2">
<img class="w-5 flex-none" src="{% static '/img/crypto/color/eos.svg' %}" alt="..." />
<a href="/pages/exchange-details.html" class="h6 stretched-link">EOS</a>
</div>
<div class="text-sm font-semibold mt-3">
7.890,00 EOS
</div>
<div class="d-flex align-items-center gap-2 mt-1 text-xs">
<span class="badge badge-xs rounded-pill text-bg-danger">
<i class="bi bi-arrow-up-right"></i>
</span>
<span>-2.2%</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,128 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>Satoshi - DeFi and Crypto Exchange Theme</title>
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
</head>
<body class="bg-surface-secondary">
<div class="d-flex flex-column flex-lg-row h-lg-full">
<div class="flex-lg-fill overflow-x-auto vstack h-lg-screen">
<div class="flex-fill overflow-y-lg-auto scrollbar bg-surface-primary rounded-top-4 rounded-top-start-lg-4 rounded-top-end-lg-0 border-top border-lg shadow">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<div class="modal fade show" id="cryptoModal" tabindex="-1" aria-labelledby="cryptoModalLabel" style="display: block" aria-modal="true" role="dialog">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content overflow-hidden">
<div class="modal-body p-0">
<div class="p-2">
<div class="vstack">
<div class="position-relative d-flex gap-3 p-4 rounded bg-light-hover">
<div class="icon flex-none">
<img src="{% static '/img/crypto/color/btc.svg' %}" class="w-10 h-10" alt="Pay with Bitcoin" />
</div>
<div class="d-flex flex-fill">
<div class="">
<a href="#" class="stretched-link text-heading font-bold">BTC</a>
<span class="d-block text-muted text-sm">Bitcoin</span>
</div>
<div class="ms-auto font-bold text-heading">
23.8
</div>
</div>
</div>
<div class="position-relative d-flex gap-3 p-4 rounded bg-light-hover">
<div class="icon flex-none">
<img src="{% static '/img/crypto/color/eth.svg' %}" class="w-10 h-10" alt="..." />
</div>
<div class="d-flex flex-fill">
<div class="">
<a href="#" class="stretched-link text-heading font-bold">ETH</a>
<span class="d-block text-muted text-sm">Ethereum</span>
</div>
<div class="ms-auto font-bold text-heading">
1.200,50
</div>
</div>
</div>
<div class="position-relative d-flex gap-3 p-4 rounded bg-light-hover">
<div class="icon flex-none">
<img src="/img/crypto/color/ada.svg" class="w-10 h-10" alt="..." />
</div>
<div class="d-flex flex-fill">
<div class="">
<a href="#" class="stretched-link text-heading font-bold">ADA</a>
<span class="d-block text-muted text-sm">Cardano</span>
</div>
<div class="ms-auto font-bold text-heading">
10.930,00
</div>
</div>
</div>
<div class="position-relative d-flex gap-3 p-4 rounded bg-light-hover">
<div class="icon flex-none">
<img src="/img/crypto/color/bnb.svg" class="w-10 h-10" alt="..." />
</div>
<div class="d-flex flex-fill">
<div class="">
<a href="#" class="stretched-link text-heading font-bold">BNB</a>
<span class="d-block text-muted text-sm">Binance</span>
</div>
<div class="ms-auto font-bold text-heading">
200
</div>
</div>
</div>
<div class="position-relative d-flex gap-3 p-4 rounded bg-light-hover">
<div class="icon flex-none">
<img src="/img/crypto/color/chain.svg" class="w-10 h-10" alt="..." />
</div>
<div class="d-flex flex-fill">
<div class="">
<a href="#" class="stretched-link text-heading font-bold">CHAIN</a>
<span class="d-block text-muted text-sm">Linkchain</span>
</div>
<div class="ms-auto font-bold text-heading">
200
</div>
</div>
</div>
</div>
</div>
<div class="px-6 py-5 bg-light d-flex justify-content-center">
<button class="btn btn-sm btn-dark rounded-pill">
<i class="bi bi-gear me-2"></i>Manage tokens
</button>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,85 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="light">
<title>Satoshi - DeFi and Crypto Exchange Theme</title>
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/inv.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/styles.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
</head>
<body class="bg-surface-secondary">
<div class="d-flex flex-column flex-lg-row h-lg-full">
<div class="flex-lg-fill overflow-x-auto vstack h-lg-screen">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<div class="textElements">
<img class="mb-6 mt-6 mb-xl-10" src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" alt="">
<h2 >Invoice #{{invoice.invoiceID}}, {{invoice.invoiceAmount}} {{invoice.invoiceCoin}}</h2>
<p>Sold by <a href="{{vendor.vendorWebAddr}}" style="text-decoration: none;">{{vendor.vendorWebName}}</a></p>
<p class="mb-6">Feedback: &#9733;&#9733;&#9733;&#9733;&#9733; 100%</p>
</div>
<div class="containerCrypto">
<div class="outer-square">
{% for coin in coins %}
<div class="inner-square">
<img class="image" src="{% static '/img/crypto/color/'|add:coin.coin|add:'.svg' %}" alt="Bitcoin Logo" width="50" height="50">
<div class="crypto-info">
<h1>{{coin.coin}}</h1>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="container2">
<div class="footer2">
<a href="#">
<p>Need support?</p>
</a>
<a href="#">
<p>Merchant API</p>
</a>
</div>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1,89 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="light">
<title>Satoshi - DeFi and Crypto Exchange Theme</title>
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/styles.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
</head>
<body class="bg-surface-secondary">
<div class="d-flex flex-column flex-lg-row h-lg-full">
<div class="flex-lg-fill overflow-x-auto vstack h-lg-screen">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<div class="modal fade show" id="cryptoModal" tabindex="-1" aria-labelledby="cryptoModalLabel" style="display: block" aria-modal="true" role="dialog">
<div class="textElements">
<img class="mb-6 mt-6 mb-xl-10" src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" alt="">
<h2 >Invoice #{{invoice.invoiceID}}, {{invoice.invoiceAmount}} {{invoice.invoiceCoin}}</h2>
<p>Sold by <a href="{{vendor.vendorWebAddr}}" style="text-decoration: none;">{{vendor.vendorWebName}}</a></p>
<p class="mb-6">Feedback: &#9733;&#9733;&#9733;&#9733;&#9733; 100%</p>
</div>
<div class="containerCrypto">
<div class="selectorContainer" style="padding-left: auto;">
{% for coin in coins %}
<div class="line" style="padding-bottom: 10px;">
<a href="">
<div class="crypto">
<img src="{% static '/img/crypto/color/'|add:coin.coin|add:'.svg' %}">
<div class="crypto-info">
<h1>Bitcoin</h1>
<p>{{coin.coin}}</p>
</div>
</div>
</a>
</div>
{% endfor %}
</div>
</div>
<div class="container2">
<div class="footer2">
<a href="#">
<p>Need support?</p>
</a>
<a href="#">
<p>Merchant API</p>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1,93 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>{% block title %} {{ title }} {% endblock title %} | Litepay.ch </title>
<!-- App favicon -->
<link rel="shortcut icon" href="{% static 'images/favicon.ico'%}">
{% block css %}
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
{% endblock css %}
</head>
<body>
<div class="row g-0 justify-content-center gradient-bottom-right start-purple-500 middle-indigo-500 end-pink-500">
<div class="col-md-6 col-lg-5 col-xl-5 position-fixed start-0 top-0 h-screen overflow-y-hidden d-none d-lg-flex flex-lg-column">
<div class="p-12 py-xl-10 px-xl-20">
<a class="d-block" href="{% url 'dashboard' %}">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_white_small.png" class="h-10" alt="...">
</a>
<div class="mt-16">
<h1 class="ls-tight font-bolder display-6 text-white mb-5">
Accept crypto currencies
<span class="d-xxl-block"> easy!</span>
</h1>
<p class="text-white text-opacity-80 pe-xl-24">
Login or register to start :-)
</p>
</div>
</div>
<div class="mt-auto ps-16 ps-xl-20">
<img class="img-fluid rounded-top-start-4" alt="..." src="https://ik.imagekit.io/litepaych/assets/new/img/hero_8.png " />
</div>
</div>
<div class="col-12 col-md-12 col-lg-7 offset-lg-5 min-h-screen overflow-y-auto d-flex flex-column justify-content-center position-relative bg-surface-primary rounded-top-start-lg-4 border-start-lg shadow-soft-5">
<div class="w-md-1/2 w-xxl-2/5 mx-auto px-10 px-md-0 py-10">
<div class="mb-10">
<a class="d-inline-block d-lg-none mb-10" href="">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" class="h-10" alt="...">
</a>
<h1 class="ls-tight font-bolder h3">
Sign in to your account
</h1>
<div class="mt-3 text-sm text-muted">
<span>Don't have an account?</span>
<a href="{% url 'register' %}" class="font-semibold">Sign up</a>.
</div>
</div>
<form action="" method="post">
{% csrf_token %}
<div class="mb-5">
<label class="form-label" for="email">Email address</label>
<input type="text" class="form-control" name="email" autofocus autocapitalize="none" autocomplete="email" maxlength="254" required id="email">
</div>
<div class="mb-5">
<div class="d-flex justify-content-between gap-2 mb-2 align-items-center">
<label class="form-label mb-0" for="id_auth-password">Password</label>
<a href="{% url 'password_reset' %}" class="text-sm text-muted text-primary-hover text-underline">Forgot password?</a>
</div>
<input type="password" class="form-control" type="password" name="password" autocomplete="password" required id="password">
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
<!-- messages -->
{% if messages %}
<ul class="messages text-center">
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</p>
{% endfor %}
</ul>
{% endif %}
</div>
</body>
</html>

View File

@ -0,0 +1,86 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>{% block title %}{% endblock title %} | Litepay.ch </title>
<!-- App favicon -->
<link rel="shortcut icon" href="{% static 'images/favicon.ico'%}">
{% block css %}
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
{% endblock css %}
</head>
<body>
<div class="row g-0 justify-content-center gradient-bottom-right start-purple-500 middle-indigo-500 end-pink-500">
<div class="col-md-6 col-lg-5 col-xl-5 position-fixed start-0 top-0 h-screen overflow-y-hidden d-none d-lg-flex flex-lg-column">
<div class="p-12 py-xl-10 px-xl-20">
<a class="d-block" href="{% url 'dashboard' %}">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_white_small.png" class="h-10" alt="...">
</a>
<div class="mt-16">
<h1 class="ls-tight font-bolder display-6 text-white mb-5">
Accept crypto currencies
<span class="d-xxl-block"> easy!</span>
</h1>
<p class="text-white text-opacity-80 pe-xl-24">
Login or register to start :-)
</p>
</div>
</div>
<div class="mt-auto ps-16 ps-xl-20">
<img class="img-fluid rounded-top-start-4" alt="..." src="https://ik.imagekit.io/litepaych/assets/new/img/hero_8.png " />
</div>
</div>
<div class="col-12 col-md-12 col-lg-7 offset-lg-5 min-h-screen overflow-y-auto d-flex flex-column justify-content-center position-relative bg-surface-primary rounded-top-start-lg-4 border-start-lg shadow-soft-5">
<div class="w-md-1/2 w-xxl-2/5 mx-auto px-10 px-md-0 py-10">
<div class="mb-10">
<a class="d-inline-block d-lg-none mb-10" href="">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" class="h-10" alt="...">
</a>
<h1 class="ls-tight font-bolder h3">
Reset your password
</h1>
<div class="mt-3 text-sm text-muted">
<span>Don't have an account?</span>
<a href="{% url 'register' %}" class="font-semibold">Sign up</a>.
</div>
</div>
<form action="" method="post">
{% csrf_token %}
<div class="mb-5">
<label class="form-label" for="email">Email address</label>
<input type="text" class="form-control" name="email" autofocus autocapitalize="none" autocomplete="email" maxlength="254" required id="email">
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
<!-- messages -->
{% if messages %}
<ul class="messages text-center">
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</p>
{% endfor %}
</ul>
{% endif %}
</div>
</body>
</html>

View File

@ -0,0 +1,93 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>{% block title %}{% endblock title %} | Litepay.ch </title>
<!-- App favicon -->
<link rel="shortcut icon" href="{% static 'images/favicon.ico'%}">
{% block css %}
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
{% endblock css %}
</head>
<body>
<div class="row g-0 justify-content-center gradient-bottom-right start-purple-500 middle-indigo-500 end-pink-500">
<div class="col-md-6 col-lg-5 col-xl-5 position-fixed start-0 top-0 h-screen overflow-y-hidden d-none d-lg-flex flex-lg-column">
<div class="p-12 py-xl-10 px-xl-20">
<a class="d-block" href="{% url 'dashboard' %}">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_white_small.png" class="h-10" alt="...">
</a>
<div class="mt-16">
<h1 class="ls-tight font-bolder display-6 text-white mb-5">
Accept crypto currencies
<span class="d-xxl-block"> easy!</span>
</h1>
<p class="text-white text-opacity-80 pe-xl-24">
Login or register to start :-)
</p>
</div>
</div>
<div class="mt-auto ps-16 ps-xl-20">
<img class="img-fluid rounded-top-start-4" alt="..." src="https://ik.imagekit.io/litepaych/assets/new/img/hero_8.png " />
</div>
</div>
<div class="col-12 col-md-12 col-lg-7 offset-lg-5 min-h-screen overflow-y-auto d-flex flex-column justify-content-center position-relative bg-surface-primary rounded-top-start-lg-4 border-start-lg shadow-soft-5">
<div class="w-md-1/2 w-xxl-2/5 mx-auto px-10 px-md-0 py-10">
<div class="mb-10">
<a class="d-inline-block d-lg-none mb-10" href="">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" class="h-10" alt="...">
</a>
<h1 class="ls-tight font-bolder h3">
Input your new password
</h1>
<div class="mt-3 text-sm text-muted">
<span>Don't have an account?</span>
<a href="{% url 'register' %}" class="font-semibold">Sign up</a>.
</div>
</div>
<form action="" method="post">
{% csrf_token %}
<div class="mb-5">
<label class="form-label" for="id_new_password1">New Password</label>
<input type="password" name="new_password1" autocomplete="new-password" class="form-control" required id="id_new_password1" placeholder="Enter password"/>
</div>
<div class="mb-5">
<div class="d-flex justify-content-between gap-2 mb-2 align-items-center">
<label class="form-label mb-0" for="id_auth-id_new_password2">New Password Confirmation</label>
</div>
<input type="password" class="form-control" type="password" name="new_password2" autocomplete="password" required id="new_password2" placeholder="Confirm password">
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
<!-- messages -->
<div >
{% if messages %}
<ul class="messages text-center">
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</p>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,125 @@
{% load static %}
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="dark light">
<title>{% block title %} {{title}} {% endblock title %} | Litepay.ch </title>
<!-- App favicon -->
<link rel="shortcut icon" href="{% static 'images/favicon.ico'%}">
{% block css %}
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="{% static '/css/main.css'%}">
<link rel="stylesheet" type="text/css" href="{% static '/css/utility.css'%}">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<!-- Fonts -->
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f=satoshi@900,700,500,300,401,400&display=swap">
{% endblock css %}
</head>
<body>
<div class="row g-0 justify-content-center gradient-bottom-right start-purple-500 middle-indigo-500 end-pink-500">
<div class="col-md-6 col-lg-5 col-xl-5 position-fixed start-0 top-0 h-screen overflow-y-hidden d-none d-lg-flex flex-lg-column">
<div class="p-12 py-xl-10 px-xl-20">
<a class="d-block" href="{% url 'dashboard' %}">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_white_small.png" class="h-10" alt="...">
</a>
<div class="mt-16">
<h1 class="ls-tight font-bolder display-6 text-white mb-5">
Accept crypto currencies
<span class="d-xxl-block"> easy!</span>
</h1>
<p class="text-white text-opacity-80 pe-xl-24">
Login or register to start :-)
</p>
</div>
</div>
<div class="mt-auto ps-16 ps-xl-20">
<img class="img-fluid rounded-top-start-4" alt="..." src="https://ik.imagekit.io/litepaych/assets/new/img/hero_8.png" />
</div>
</div>
<div class="col-12 col-md-12 col-lg-7 offset-lg-5 min-h-screen overflow-y-auto d-flex flex-column justify-content-center position-relative bg-surface-primary rounded-top-start-lg-4 border-start-lg shadow-soft-5">
<div class="w-md-1/2 w-xxl-2/5 mx-auto px-10 px-md-0 py-10">
<div class="mb-10">
<a class="d-inline-block d-lg-none mb-10" href="/pages/dashboard.html">
<img src="https://ik.imagekit.io/litepaych/assets/new/img/logo_litepay_2020_blue.png" class="h-10" alt="...">
</a>
<h1 class="ls-tight font-bolder h3">
Get started. It&#39;s free
</h1>
<div class="mt-3 text-sm text-muted">
<span>Already have an account?</span>
<a href="{% url 'login' %}" class="font-semibold">Sign in</a> to your account.
</div>
</div>
<form action="" method="post">
{% csrf_token %}
<div class="row g-5">
<div class="col-sm-6">
<label class="form-label">First name</label>
<input type="text" class="form-control" name="first_name"/>
{% if form.first_name.errors %}
{% for error in form.first_name.errors %}
<small class="text-danger">{{ error|escape }}</small>
{% endfor %}
{% endif %}
</div>
<div class="col-sm-6">
<label class="form-label">Last name</label>
<input type="text" class="form-control" name="last_name"/>
{% if form.last_name.errors %}
{% for error in form.last_name.errors %}
<small class="text-danger">{{ error|escape }}</small>
{% endfor %}
{% endif %}
</div>
<div class="col-sm-12">
<label class="form-label" for="email">Email address</label>
<input type="email" class="form-control" name="email" autofocus autocapitalize="none" autocomplete="email" maxlength="254" required id="email" />
{% if form.email.errors %}
{% for error in form.email.errors %}
<small class="text-danger">{{ error|escape }}</small>
{% endfor %}
{% endif %}
</div>
<div class="col-sm-12">
<label class="form-label">Password</label>
<input type="password" class="form-control" type="password" name="password" required id="password"/>
{% if form.password.error %}
{% for error in form.password.errors %}
<small class="text-danger">{{ error|escape }}</small>
{% endfor %}
{% endif %}
</div>
<div class="col-sm-12">
<label class="form-label">Password Again</label>
<input type="password" type="password_again" class="form-control" name="password_again" required id="password_again" />
</div>
<div class="col-sm-12 text-center">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
{% for error in form.non_field_errors %}
<small class="text-danger text-center">{{ error|escape }}</small>
{% endfor %}
<!-- messages -->
{% if messages %}
<ul class="messages text-center">
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</p>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</body>
</html>

View File

View File

@ -0,0 +1,156 @@
{% extends "partials/base.html" %}
{% load static %}
{% block title %}Vendor Edit Page{% endblock title %}
{% block content %}
<!-- ============================================================== -->
<!-- Start right Content here -->
<!-- ============================================================== -->
<!-- Main content -->
<div class="flex-fill overflow-y-lg-auto scrollbar bg-surface-primary rounded-top-4 rounded-top-start-lg-4 rounded-top-end-lg-0 border-top border-lg shadow">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<header class="border-bottom mb-10">
<div class="row align-items-center">
<div class="col-sm-6 col-12">
<h1 class="h2 ls-tight">
{% block vendor_title %} {{vendor_title}} {% endblock vendor_title %}
</h1>
</div>
</div>
<ul class="nav nav-tabs overflow-x border-0 mt-4">
<li class="nav-item">
<a href="{% url 'edit-vendor' vendors.vendorUUID %}" class="nav-link">Options</a>
</li>
<li class="nav-item">
<a href="{% url 'add-address' vendors.vendorUUID %}" class="nav-link">Addresses</a>
<li class="nav-item">
<a href="/pages/account-billing.html" class="nav-link">Delete</a>
</li>
</ul>
</header>
<form method="POST" action="">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="form-group row">
<div class="col-md-2">
<label for="coin" class="form-label"> Coins <span><i class="bi bi-patch-question-fill text-danger" title="Choose what coin to accept!"></i></span></label>
</div>
<div class="col-md-8 col-xl-2">
<select id="coin" name="coin" class="form-select" aria-describedby="select coin">
{% for coin in coins %}
<option value="{{coin.coinSymbol}}"> {{ coin.coinName }} ({{ coin.coinSymbol }}) </option>
{% endfor %}
</select>
{% if form.coin.errors %}
{% for error in form.coin.errors %}
<span id="coinHelpBlock" class="text-danger">{{ error|escape }}</span>
{% endfor %}
{% endif %}
</div>
</div>
<p class="my-6" />
<div class="row align-items-center">
<div class="col-md-2">
<label for="address" class="form-label"> Address <span><i class="bi bi-patch-question-fill text-danger" title="Where the funds are sent to"></i></span></label>
</div>
<div class="col-md-8 col-xl-5">
<div class="">
<div class="input-group position-relative">
<input id="address" name="address" type="text" class="form-control" placeholder="Address" aria-label="address">
</div>
{% if form.address.errors %}
{% for error in form.address.errors %}
<p >{{ error|escape }}</p>
{% endfor %}
{% endif %}
</div>
</div>
</div>
<p class="my-6" />
<div class="form-group row">
<div class="offset-4 col-8">
<input name="submit" type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
</form>
<!-- table for addresses -->
<p class="my-10"></p>
<div class="col-sm-6 col-12">
<h1 class="h2 ls-tight">
Addresses
</h1>
</div>
<div class="table-responsive">
<table class="table table-hover table-nowrap">
<thead class="thead-light">
<tr>
<th scope="col">Coin</th>
<th scope="col">Address</th>
<th scope="col">Added</th>
<th scope="col">Active</th>
</tr>
</thead>
{% for address in addresses %}
<tr>
<td>
<img class="w-5 flex-none"src="{% static '/img/crypto/color/'|add:address.coin|add:'.svg' %}" alt="{{address.coin}}" >
</td>
<td>
{{address.address}}
</td>
<td>
{{address.addrAddDate|timesince}} ago
</td>
<td>
{% if address.addrIsActive == False %}
<span class="badge badge-lg badge-dot">
<i class="bg-warning"></i> Inactive
</span>
{% else %}
<span class="badge badge-lg badge-dot">
<i class="bg-success"></i> Active
</span>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- Dashboard -->
<!-- End Page-content -->
<!-- end main content-->
{% endblock content %}

View File

@ -0,0 +1,175 @@
{% extends "partials/base.html" %}
{% load static %}
{% block title %}Vendor Edit Page{% endblock title %}
{% block content %}
<!-- ============================================================== -->
<!-- Start right Content here -->
<!-- ============================================================== -->
<!-- Main content -->
<div class="flex-fill overflow-y-lg-auto scrollbar bg-surface-primary rounded-top-4 rounded-top-start-lg-4 rounded-top-end-lg-0 border-top border-lg shadow">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<header class="border-bottom mb-10">
<div class="row align-items-center">
<div class="col-sm-6 col-12">
<h1 class="h2 ls-tight">
{% block vendor_title %} {{vendor_title}} {% endblock vendor_title %}
</h1>
</div>
</div>
<ul class="nav nav-tabs overflow-x border-0 mt-4">
<li class="nav-item">
<a href="#" class="nav-link">Options</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">Addresses</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">Delete</a>
</li>
</ul>
</header>
<form method="POST" action="">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="row align-items-center">
<div class="col-md-2">
{{ form.vendorWebName.errors }}
<label for="{{ form.vendorWebName.id_for_label}}" class="form-label">Website Name <span><i class="bi bi-patch-question-fill text-danger" title="Shown on invoice page"></i></span></label>
</div>
<div class="col-md-8 col-xl-5">
<div class="">
<div class="input-group position-relative">
<span class="input-group-text"><i class="bi bi-three-dots"></i></span>
<input id="vendorWebName" name="vendorWebName" type="text" class="form-control" placeholder="Website Name" aria-label="vendorWebName">
</div>
{{ form.vendorWebName }}
</div>
</div>
</div>
<p class="my-6" />
<div class="row align-items-center">
<div class="col-md-2">
{{ form.vendorWebAddr.errors }}
<label for="{{ form.vendorWebAddr.id_for_label}}" class="form-label">Website URL <span><i class="bi bi-patch-question-fill text-danger" title="Shown on invoice page"></i></span></label>
</div>
<div class="col-md-8 col-xl-5">
<div class="">
<div class="input-group position-relative">
<span class="input-group-text"><i class="bi bi-window"></i></span>
<input id="vendorWebAddr" name="vendorWebAddr" type="text" class="form-control" placeholder="Website URL" aria-label="vendorWebAddr">
</div>
{{ form.vendorWebAddr }}
</div>
</div>
</div>
<p class="my-6" />
<div class="row align-items-center">
<div class="col-md-2">
<label for="vendorNetworkFee" class="form-label">Network Fee % <span><i class="bi bi-patch-question-fill text-danger" title="Max percentage "></i></span> </label>
</div>
<div class="col-md-8 col-xl-2">
<select id="vendorNetworkFee" name="vendorNetworkFee" class="form-select" aria-describedby="vendorNetworkFeeHelpBlock">
<option value="0" selected="selected">0%</option>
<option value="5">5%</option>
<option value="10">10%</option>
</select>
{% if form.vendorNetworkFee.errors %}
{% for error in form.vendorNetworkFee.errors %}
<span id="vendorNetworkFeeHelpBlock" class="text-danger">{{ error|escape }}</span>
{% endfor %}
{% endif %}
</div>
</div>
<p class="my-6" />
<div class="row align-items-center">
<div class="col-md-2">
<label for="vendorPaidNotification" class="form-label">Notifications <span><i class="bi bi-patch-question-fill text-danger" title="Get notified by email for each payment received?"></i></span></label>
</div>
<div class="col-md-8 col-xl-2">
<select id="vendorPaidNotification" name="vendorPaidNotification" class="form-select" aria-describedby="vendorPaidNotificationHelpBlock">
<option value="true" selected="selected">Yes</option>
<option value="false">No</option>
</select>
</div>
{% if form.vendorPaidNotification.errors %}
{% for error in form.vendorPaidNotification.errors %}
<span id="vendorPaidNotificationHelpBlock" class="text-danger">{{ error|escape }}</span>
{% endfor %}
{% endif %}
</div>
<p class="my-6" />
<div class="row align-items-center">
<div class="col-md-2">
<label for="vendorCoverAmount" class="form-label">Cover Amount <span><i class="bi bi-patch-question-fill text-danger" title="Amount covered by you in case the buyer sends less than required"></i></span> </label>
</div>
<div class="col-md-8 col-xl-2">
<select id="vendorCoverAmount" name="vendorCoverAmount" class="form-select" aria-describedby="vendorCoverAmountHelpBlock">
<option value="0" >0%</option>
<option value="1" selected="selected">1%</option>
<option value="2">2%</option>
<option value="3">3%</option>
<option value="4">4%</option>
<option value="5">5%</option>
<option value="6">6%</option>
<option value="7">7%</option>
<option value="8">8%</option>
<option value="9">9%</option>
<option value="10">10%</option>
</select>
{% if form.vendorCoverAmount.errors %}
{% for error in form.vendorCoverAmount.errors %}
<span id="vendorCoverAmountHelpBlock" class="text-danger">{{ error|escape }}</span>
{% endfor %}
{% endif %}
</div>
</div>
<p class="my-6" />
<div class="form-group row">
<div class="col-md-2">
<label for="vendorPayWindow" class="form-label">Payment <span><i class="bi bi-patch-question-fill text-danger" title="When should we send you your payments?"></i></span></label>
</div>
<div class="col-md-8 col-xl-2">
<select id="vendorPayWindow" name="vendorPayWindow" class="form-select" aria-describedby="vendorPayWindowHelpBlock">
<option value="true" >Hourly</option>
<option value="false" selected="selected">Daily</option>
</select>
{% if form.vendorPayWindow.errors %}
{% for error in form.vendorPayWindow.errors %}
<span id="vendorPayWindowHelpBlock" class="text-danger">{{ error|escape }}</span>
{% endfor %}
{% endif %}
</div>
</div>
<hr class="my-6" />
<div class="form-group row">
<div class="offset-4 col-8">
<input name="submit" type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
</form>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- Dashboard -->
<!-- End Page-content -->
<!-- end main content-->
{% endblock content %}

View File

@ -0,0 +1,51 @@
{% extends "partials/base.html" %}
{% load static %}
{% block title %}Vendor Edit Page{% endblock title %}
{% block content %}
<!-- ============================================================== -->
<!-- Start right Content here -->
<!-- ============================================================== -->
<!-- Main content -->
<div class="flex-fill overflow-y-lg-auto scrollbar bg-surface-primary rounded-top-4 rounded-top-start-lg-4 rounded-top-end-lg-0 border-top border-lg shadow">
<main class="container-fluid px-3 py-5 p-lg-6 p-xxl-10">
<header class="mb-10">
<div class="row align-items-center">
<div class="col-sm-6 col-12">
<h1 class="h2 ls-tight">
{% block vendor_title %} {{vendor_title}} {% endblock vendor_title %}
</h1>
</div>
</div>
<p class="my-6"></p>
</header>
<div class="position-relative p-5 text-center text-muted bg-body border border-dashed rounded-5">
<svg class="bi mt-5 mb-3" width="48" height="48"><use xlink:href="#check2-circle"></use></svg>
<h1 class="text-body-emphasis">Your vendor has been created!</h1>
<p class="col-lg-6 mx-auto mb-4 "> Please save the SecretKey as you won't be able to see it again! </p>
<p class="col-lg-6 mx-auto "> VendorID: <strong> {{vendor.vendor}} </strong></p>
<p class="col-lg-6 mx-auto mb-4 "> SecretKey: <strong> {{secret}} </strong></p>
<p class="col-lg-12 mx-auto mb-8 "> Whats next? Go to Addresses tab and input your crypto addresses. </p>
<a class="btn btn-primary rounded-pill" href="{% url 'edit-vendor' vendor.vendorUUID %}"> Lets go! </a>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- Dashboard -->
<!-- End Page-content -->
<!-- end main content-->
{% endblock content %}

View File

@ -0,0 +1,10 @@
{% autoescape off %}
Hi {{ user.username }},
Welcome to Litepay.ch
Please click on the link below to confirm your registration:
http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{% endautoescape %}

View File

@ -0,0 +1,16 @@
{% autoescape off %}
Hello {{ user }},
To initiate the password reset process for your {{ user.email }} on Litepay.ch,
please click the link below:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
If clicking the link above doesn't work, please copy and paste the URL in a new browser
window instead.
Sincerely,
The Litepay.ch team
{% endautoescape %}

0
base/tests.py Normal file → Executable file
View File

11
base/tokens.py Executable file
View File

@ -0,0 +1,11 @@
from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active)
)
account_activation_token = AccountActivationTokenGenerator()

16
base/urls.py Normal file → Executable file
View File

@ -1,18 +1,26 @@
from . import views
from django.urls import path
from django.urls import path, include
from django.contrib.auth import views as auth_views
urlpatterns = [
path('login/', views.LoginPage, name="login"),
path('logout/', views.LogoutPage, name="logout"),
path('account/login/', views.LoginPage, name="login"),
path('account/logout/', views.LogoutPage, name="logout"),
path('account/register/', views.RegiserUser, name="register"),
path('account/activate/<uidb64>/<token>', views.activate, name='activate'),
path('account/password_reset', views.password_reset_request, name="password_reset"),
path('account/reset/<uidb64>/<token>/', views.passwordResetConfirm, name='password_reset_confirm'),
path('', views.index, name="dashboard"),
path('vendor/', views.VendorPage, name="vendor"),
path('vendor/edit/<str:vdr>/', views.VendorEditPage, name="edit-vendor"),
path('vendor/create', views.VendorCreatePage, name="create-vendor"),
path('vendor/address/<str:vdr>/', views.VendorAddrPage, name="add-address"),
path('p/', views.MerchInvoice, name="invoice-create"),
#path('vendor-success', views.VendorSuccess, name="vendor-success")
path('ipage/<str:inv>/', views.InvoicePage, name="ipage"),
path('api', views.ApiInvoice, name='api-invoice-create')
]

371
base/views.py Normal file → Executable file
View File

@ -2,23 +2,100 @@ from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.db.models import Q
from django_otp.decorators import otp_required
#
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse, JsonResponse
#reg
from django.template.loader import render_to_string
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
from django.core.mail import EmailMessage
#from django_otp.decorators import otp_required
#from django.contrib.auth.views import PasswordResetView
#from django.contrib.messages.views import SuccessMessageMixin
#from django.core.exceptions import ValidationError
#from django.urls import reverse_lazy
#from django.contrib.auth.models import BaseUserManager
# custom
from .tokens import account_activation_token
from users.models import User
from .models import VendorsData, CryptoCoins, VendorsAddresses
from .forms import VendorEditForm, VendorAddrAddForm
from .functions import vendor_generator, checksumCheck
import uuid, hashlib
from .models import VendorsData, CryptoCoins, VendorsAddresses, InvoiceCreation
from .forms import VendorEditForm, VendorAddrAddForm, UserRegistrationForm, PasswordResetForm, SetPasswordForm, InvoiceCreationForm, ApiPaymentCreationForm
from .functions import vendor_generator, checksumCheck, UrlValidator, RPCHost, RPCXMR
from .rpcs import rpcs, API_FEE
import uuid, hashlib, requests
# Create your views here.
def activateEmail(request, user, to_email):
mail_subject = 'Activate your user account.'
message = render_to_string('base/template_activate_account.html', {
'user': user.username,
'domain': get_current_site(request).domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
'protocol': 'https' if request.is_secure() else 'http'
})
email = EmailMessage(mail_subject, message, to=[to_email])
if email.send():
messages.success(request, f'Congrats, please check your email and activate your account by \
clicking on the activation link. Rememeber to check all folders')
else:
messages.error(request, f' Unable to send the activation email, please check and retry.')
def activate(request, uidb64, token):
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
messages.success(request, 'Thank you for your email confirmation. Now you can login your account.')
else:
messages.error(request, 'Activation link is invalid!')
return redirect('login')
@login_required(login_url='login')
#@otp_required()
def index(request):
context = {}
return render(request, 'base/dashboard.html', context)
return render(request, 'base/lp_dashboard.html', context)
def RegiserUser(request):
title = "Register your account"
if request.method == "POST":
if request.POST.get('password') != request.POST.get('password_again'):
messages.error(request, 'Password does not match')
return redirect('register')
form = UserRegistrationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.email = form.cleaned_data['email'].lower()
user.set_password(form.cleaned_data['password'])
user.last_name = form.cleaned_data['last_name']
user.first_name = form.cleaned_data['first_name']
user.uuid = uuid.uuid4()
user.is_active = False
user.save()
activateEmail(request, user, form.cleaned_data.get('email'))
return redirect('login')
else:
form = UserRegistrationForm()
context = {"form": form, 'title': title}
return render(request, 'base/lp_register.html', context)
def LoginPage(request):
if request.method == 'POST':
@ -29,7 +106,7 @@ def LoginPage(request):
try:
user = User.objects.get(email=email)
except:
error = messages.error(request, 'Email not registered')
error = messages.error(request, 'Wrong password or account is inactive')
if user is not None and error is None:
user = authenticate(request, email=email, password=password)
@ -37,21 +114,87 @@ def LoginPage(request):
login(request, user)
return redirect('dashboard')
else:
messages.error(request, 'Wrong password')
messages.error(request, 'Wrong password or account is inactive')
context = {}
return render(request, 'base/loogin2.html', context)
context = {'title': 'Sign In'}
return render(request, 'base/lp_login.html', context)
def LogoutPage(request):
logout(request)
return redirect('login')
def password_reset_request(request):
title = "Password reset"
if request.method == 'POST':
form = PasswordResetForm(request.POST)
user = None
if form.is_valid():
email = form.cleaned_data['email'].lower()
try:
user = User.objects.get(email=email)
except:
messages.success(request, 'If the email is registered with us, you will receive an email with instructions for resetting your password.')
if user:
subject = "Password reset requested on Litepay.ch"
message = render_to_string("base/template_password_reset_email.html", {
'user': user,
'domain': get_current_site(request).domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
"protocol": 'https' if request.is_secure() else 'http'
})
email = EmailMessage(subject, message, to=[user.email])
if email.send():
messages.success(request,
"""
If the email is registered with us, you will receive an email with instructions for resetting your password.
"""
)
else:
messages.error(request, "Problem sending reset password email, please try again")
return redirect('login')
else:
form = PasswordResetForm()
context = {"form": form, 'title': title}
return render(request, "base/lp_pswd_reset.html", context)
def passwordResetConfirm(request, uidb64, token):
title = "Password reset"
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
if request.method == 'POST':
form = SetPasswordForm(user, request.POST)
if form.is_valid():
form.save()
messages.success(request, "Your password has been set. You may go ahead and log in.")
return redirect('login')
else:
for error in list(form.errors.values()):
messages.error(request, error)
context = {}
return render(request, 'base/lp_pswd_reset_confirm.html', context)
else:
messages.error(request, "Link is expired")
return redirect("dashboard")
#### VENDOR VIEWS ####
@login_required(login_url='login')
def VendorPage(request):
vendors = VendorsData.objects.filter(Q(vendorid_id=request.user.id) & Q(vendorDeleted=False))
context = {'vendors': vendors}
return render(request, 'base/vendor.html', context)
return render(request, 'base/lp_vendor.html', context)
@login_required(login_url='login')
#@otp_required(login_url='two_factor:login')
@ -74,7 +217,7 @@ def VendorEditPage(request, vdr ):
except Exception as e:
messages.error(request, "Something wrong happened, try again.")
context = {'vendors': vendors, 'form': form, 'vendor_title': vendor_title}
return render(request, 'base/vendorEdit.html', context)
return render(request, 'base/lp_vendorEdit.html', context)
except Exception as e:
messages.error(request, e)
return redirect('vendor')
@ -117,14 +260,14 @@ def VendorCreatePage(request):
new_vendor.save()
vendor_title = "Congrats!"
context = {'vendor_title': vendor_title, "vendor": new_vendor, 'secret': secretKey}
return render(request, 'base/vendorSuccess.html', context)
return render(request, 'base/lp_vendorSuccess.html', context)
except Exception:
messages.error(request, "Unable to create vendor") #
else:
messages.error(request, "The information submited is incomplete") #
except Exception as e:
messages.error(request, "Something wrong happened, try again.")
return render(request, 'base/vendorCreate.html', context)
return render(request, 'base/lp_vendorCreate.html', context)
@login_required(login_url='login')
def VendorAddrPage(request,vdr):
@ -142,14 +285,22 @@ def VendorAddrPage(request,vdr):
if request.POST.get('submit') == 'Submit':
try:
if checksumCheck(request.POST.get('coin').lower(), request.POST.get('address')) == False:
messages.error(request, "Invalid address")
messages.error(request, "Invalid address, please try again")
context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses}
return render(request, 'base/vendorAddr.html', context)
return render(request, 'base/lp_vendorAddr.html', context)
except:
# stop here, return nothing, notify us.
return redirect('vendorAddr', vdr)
##check if duplicate
##check if duplicate
try:
for obj in VendorsAddresses.objects.filter(Q(coin=request.POST.get('coin')) & Q(addrIsActive=True) & Q(vendorUUID=vdr) & Q(vendorid_id=request.user.id)):
if obj.address == request.POST.get('address'):
messages.error(request, "Address already exists")
context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses}
return render(request, 'base/lp_vendorAddr.html', context)
except:
pass
try:
form = VendorAddrAddForm(request.POST)
@ -168,7 +319,7 @@ def VendorAddrPage(request,vdr):
messages.success(request, "Vendor address saved")
#add email notification
context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses}
return render(request, 'base/vendorAddr.html', context)
return render(request, 'base/lp_vendorAddr.html', context)
except Exception as e:
messages.error(request, e) #
else:
@ -177,8 +328,182 @@ def VendorAddrPage(request,vdr):
messages.error(request, "Something wrong happened, try again!")
context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses}
return render(request, 'base/vendorAddr.html', context)
return render(request, 'base/lp_vendorAddr.html', context)
except Exception as e:
messages.error(request, "Something wrong happened, try again!")
return redirect('vendor')
@csrf_exempt
def MerchInvoice(request):
if request.method == 'GET':
return HttpResponse(status=403)
elif request.method == 'POST':
required_fields = ['vendor', 'secret', 'callback', 'return', 'invoice']
for field in required_fields:
if request.POST.get(field) is None or request.POST.get(field).strip() == '':
return JsonResponse({'status': 'error', 'message': f'You did not send the {field} field, try again.'}, status=400)
price = request.POST.get('price')
currency = request.POST.get('currency')
callbackurl = requests.utils.unquote(request.POST.get('callback'))
returnurl = requests.utils.unquote(request.POST.get('return'))
email = request.POST.get('email')
if not currency:
currency = 'USD'
if price is None or not price.isdigit() or int(price) <= 0:
return JsonResponse({'status': 'error', 'message': 'You did not send a valid price, try again.'}, status=400)
if UrlValidator.validate(requests.utils.unquote(request.POST.get('callback')))!= True:
return JsonResponse({'status': 'error', 'message': 'Invalid callback URL'}, status=400)
if UrlValidator.validate(requests.utils.unquote(request.POST.get('return'))) != True:
return JsonResponse({'status': 'error', 'message': 'Invalid return URL'}, status=400)
try:
vendor = VendorsData.objects.get(vendor=request.POST.get('vendor'))
except:
return JsonResponse({'status': 'error', 'message':'Vendor ID unknown'}, status=400)
if vendor.vendorSecretKey != hashlib.md5(request.POST.get('secret').encode()).hexdigest():
return JsonResponse({'status': 'error', 'message': 'Invalid secret key'}, status=400)
invUUID = uuid.uuid5(uuid.NAMESPACE_URL,request.POST.get('invoice')+request.POST.get('vendor'))
if InvoiceCreation.objects.filter(Q(invoiceUUID=invUUID)):
protocol = 'https' if request.is_secure() else 'http'
domain = get_current_site(request).domain + '/v2/i/' + str(invUUID)
return JsonResponse({'status': 'success', 'url': protocol +'://'+ domain }, status=200)
try:
form = InvoiceCreationForm()
newForm = form.save(commit=False)
newForm.invoiceUUID = invUUID
newForm.invoiceID = request.POST.get('invoice')
newForm.invoiceAmount = request.POST.get('price')
newForm.invoiceCoin = currency
newForm.invoiceState = 0
newForm.invoiceCallbackLink = callbackurl
newForm.invoiceReturnLink = returnurl
newForm.invoiceBuyerEmail = email
newForm.invoiceDeleteLink = None
newForm.invoiceDeleted = 0
newForm.invoiceVendor_id = vendor.id
newForm.invoiceVendorid_id = vendor.vendorid_id
try:
newForm.save()
protocol = 'https' if request.is_secure() else 'http'
domain = get_current_site(request).domain + '/v2/i/' + str(invUUID)
return JsonResponse({'status': 'success', 'url': protocol +'://'+ domain }, status=200)
except Exception as e:
return JsonResponse({'status': 'error', 'message': 'Unable to save the invoice, try again'}, status=400)
except Exception as e:
return JsonResponse({'status': 'error', 'message': 'Unable to create the invoice, try again'}, status=400)
else:
return HttpResponse(status=403)
@csrf_exempt
def ApiInvoice(request):
if request.method == 'GET':
required_fields = ['method', 'address']
for field in required_fields:
if request.GET.get(field) is None or request.GET.get(field).strip() == '':
return JsonResponse({'status': 'error', 'message': f'You did not send the {field} field, try again.'}, status=400)
try:
if not CryptoCoins.objects.filter(Q(coinAPI=True) & Q(coinIsActive=True) & Q(coinSymbol = request.GET.get('method').upper())):
return JsonResponse({'status': 'error', 'message': 'Invalid method used'}, status=400)
except Exception:
return JsonResponse({'status': 'error', 'message': 'Something wrong happened, try again!'}, status=400)
if checksumCheck(request.GET.get('method').lower(), request.GET.get('address')) == False:
return JsonResponse({'status': 'error', 'message': 'Invalid destination address'}, status=400)
if request.GET.get('callback_url'):
if UrlValidator.validate(requests.utils.unquote(request.GET.get('callback_url'))) != True:
return JsonResponse({'status': 'error', 'message': 'Invalid callback URL'}, status=400)
statusFlag = 0
callbackurl = requests.utils.unquote(request.GET.get('callback_url'))
else:
statusFlag = 1
callbackurl = None
## RPC connection to Demons
match request.GET.get('method').upper():
case 'BTC' | 'LTC' | 'ZEC' | 'BCH' | 'BTCT' | 'DOGE':
rpc = RPCHost("http://%s:%s@%s:%s" % (rpcs[request.GET.get('method').upper()]['user'], rpcs[request.GET.get('method').upper()]['pass'], rpcs[request.GET.get('method').upper()]['host'], rpcs[request.GET.get('method').upper()]['port']))
case 'XMR':
rpc = RPCXMR(rpcs[request.GET.get('method').upper()]['host'], rpcs[request.GET.get('method').upper()]['user'], rpcs[request.GET.get('method').upper()]['pass'])
case _:
return JsonResponse({'status': 'error', 'message': 'RPC undergoing maintenance'}, status=400)
try:
match request.GET.get('method').upper():
case 'XMR':
wallet = rpc.call('create_address',{"account_index": 0})
wallet = wallet['address']
case 'LTC' | 'ZEC' | 'DOGE':
#wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,False,True)
wallet = rpc.call('getnewaddress')
case 'BTC' | 'BTCT':
#wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False)
wallet = rpc.call('getnewaddress', '', 'p2sh-segwit')
case 'BCH':
wallet = rpc.call('getnewaddress')
wallet = wallet.replace('bitcoincash:', '')
case _:
## notify admin about the error
return JsonResponse({'status': 'error', 'message': 'CryptoCoin unavailable'}, status=400)
except Exception as error:
## notify admin about the error
# Failed to connect for remote procedure call.
return JsonResponse({'status': 'error', 'message': 'RPC unavailable'}, status=400)
try:
form = ApiPaymentCreationForm()
newForm = form.save(commit=False)
newForm.userUUID = uuid.uuid5(uuid.NAMESPACE_URL,request.GET.get('address'))
newForm.userAddr = request.GET.get('address')
newForm.userCoin = request.GET.get('method').upper()
newForm.usercallbackUrl = callbackurl
newForm.userIP = request.META.get("REMOTE_ADDR")
newForm.ourAddr = wallet
newForm.userAmount = 0.00000000
newForm.statusFlag = statusFlag
newForm.paidFlag = 0
try:
newForm.save()
return JsonResponse(
{'status': 'success',
'callback_url': callbackurl,
'address': wallet,
'destination': request.GET.get('address'),
'fee': API_FEE
}, status=200)
except Exception as e:
return JsonResponse({'status': 'error', 'message': 'Unable to save the invoice, try again'}, status=400)
except Exception as e:
return JsonResponse({'status': 'error', 'message': 'Unable to create the invoice, try again'}, status=400)
elif request.method == 'POST':
return HttpResponse(status=403)
else:
return HttpResponse(status=403)
def InvoicePage(request, inv):
try:
invoice = InvoiceCreation.objects.get(invoiceUUID=inv)
vendor = VendorsData.objects.get(Q(id=invoice.invoiceVendor_id))
vendorCryptoCoins = VendorsAddresses.objects.filter(Q(addrIsActive=True) & Q(vendor_id=invoice.invoiceVendor_id))
context = {'invoice': invoice, 'coins': vendorCryptoCoins, "vendor": vendor}
return render(request, 'base/lp_invoice.html', context)
except Exception as e:
return HttpResponse(e)
#return redirect('dashboard')

BIN
dLitepay/.DS_Store vendored

Binary file not shown.

0
dLitepay/__init__.py Normal file → Executable file
View File

0
dLitepay/asgi.py Normal file → Executable file
View File

7
dLitepay/settings.py Normal file → Executable file
View File

@ -192,3 +192,10 @@ SESSION_COOKIE_AGE = 3600
TWO_FACTOR_REMEMBER_COOKIE_AGE = 3600
SERVER_EMAIL = 'info@litepay.ch'
DEFAULT_FROM_EMAIL = 'info@litepay.ch'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'x'
EMAIL_HOST_PASSWORD = 'x'

5
dLitepay/urls.py Normal file → Executable file
View File

@ -19,12 +19,13 @@ from django.urls import path, include
from two_factor.urls import urlpatterns as tf_urls
urlpatterns = [
#path('', include(tf_urls)),
path('', include('base.urls'))
path('', include('base.urls')),
path('admin/', admin.site.urls),
]
'''
urlpatterns = [
path('admin/', admin.site.urls),
]
'''

0
dLitepay/wsgi.py Normal file → Executable file
View File

BIN
src/.DS_Store vendored

Binary file not shown.

77
src/css/inv.css Executable file
View File

@ -0,0 +1,77 @@
/* Define styles for centering the outer square */
body {
font-family: Arial, Helvetica, sans-serif;
display: flex;
background-color: rgb(247, 247, 247);
justify-content: center;
align-items: center;
padding: 0 0 0 30%;
width: 600px; /* Adjust for smaller screens */
height: 100vh; /* Ensure full viewport height for vertical centering */
margin: 0; /* Remove default margin */
}
/* Style for the outer square */
.outer-square {
display: flex;
flex-wrap: wrap;
flex: 1 0 21%; /* explanation below */
border-radius: 15px; /* Add rounded corners to the outer square */
}
/* Style for the nested square */
.inner-square {
width: 120px;
height: 120px;
/* background-color: white; Change the background to white */
margin: 15px; /* Add margin of 15px to push it away from the outer square's edge */
border-radius: 10%; /* Create a circle for the inner square */
/* border: 2px solid rgb(247, 247, 247); Add a blue 2px border */
position: relative; /* Enable positioning for the content */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 1%;
}
.image {
padding-top: 10%;
}
/* Style for the h1 tag */
h1 {
text-align: center;
padding: auto;
}
.crypto-info h1 {
text-decoration: none;
text-align: center;
font-size: 16px;
}
.crypto-info p {
text-decoration: none;
text-align: center;
font-size: 14px;
padding: auto;
}
.crypto-info img {
width: 50px;
height: 50px;
padding: 10px;
}
@media (max-width: 500px) {
.inner-square {
flex-direction: row;
width: 100%;
}
.crypto-info h1 {
padding-left: 10px;
padding-top: 10px;
}
}

2
src/css/main.css Executable file

File diff suppressed because one or more lines are too long

1
src/css/main.css.map Executable file

File diff suppressed because one or more lines are too long

282
src/css/styles.css Executable file
View File

@ -0,0 +1,282 @@
/* styles.css */
body {
margin: auto;
padding: 0;
background-color: rgb(247, 247, 247);
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: Arial, Helvetica, sans-serif;
width: max-content;
}
.containerCrypto {
/* background-color: rgb(254, 254, 254);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */
border-radius: 20px;
padding: 20px 20px;
text-align: center;
max-width: 80%; /* Adjust the maximum width as desired */
width: 500px; /* Set a fixed width as a fallback for smaller screens */
margin: 0 auto; /* Center the container horizontally */
}
.container3 {
background-color: rgb(254, 254, 254);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 20px;
padding: 50px;
text-align: center;
max-width: 80%; /* Adjust the maximum width as desired */
width: 500px; /* Set a fixed width as a fallback for smaller screens */
margin: 0 auto; /* Center the container horizontally */
}
.container2 {
background-color: rgb(254, 254, 254);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 15px;
padding: 1px 100px;
text-align: center;
max-width: 80%; /* Adjust the maximum width as desired */
width: 500px; /* Set a fixed width as a fallback for smaller screens */
margin: 20px auto; /* Center the container horizontally */
}
h1 {
margin: 0;
font-size: 24px;
}
h2 {
margin: 0;
font-size: 20px;
font-weight: 500;
}
p {
margin-top: 10px;
font-size: 16px;
color: #888;
}
a {
text-decoration: none;
}
.textElements {
margin: auto;
width: max-content;
text-align: center;
}
.textElements img {
width: 50%;
}
.redText {
margin-top: -6px;
color: red;
}
.selectorContainer {
margin: auto;
width: max-content;
}
.line {
display: flex;
}
.cryptos {
box-shadow: 1px 3px 8px rgba(0, 0, 0, 0.1);
border-radius: 20px;
display: flex;
align-items: center;
margin: 0 15px;
padding: 10px 40px 10px 20px;
}
.crypto img {
margin-right: 10px;
width: 65px;
height: 65px;
}
.line a {
text-decoration: none;
}
.line a h1 {
color: #000;
text-decoration: none;
}
@media (max-width: 768px) {
.container {
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 45px 10px;
text-align: center;
width: 500px; /* Set a fixed width as a fallback for smaller screens */
margin: auto; /* Center the container horizontally */
}
.container2 {
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 15px 10px;
text-align: center;
width: 500px; /* Set a fixed width as a fallback for smaller screens */
margin: 10px auto; /* Center the container horizontally */
}
.line {
margin-top: 0px;
display: block;
}
.crypto {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
display: flex;
align-items: center;
margin: 15px 15px;
padding: 5px 20px;
}
}
.footer {
justify-content: space-between;
margin-top: 50px;
margin-bottom: -35px;
padding-top: 20px;
border-top: 1px solid #ccc;
}
.footer p {
margin: 0;
font-size: 14px;
color: #888;
}
.footer2 {
display: flex;
justify-content: space-between;
}
.footer2 p {
font-size: 14px;
color: rgb(0, 167, 167);
}
/* Add the following CSS for the new element */
.row-container {
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 20px;
display: flex;
align-items: center;
margin-top: 20px;
}
.row-container img {
width: 28%;
height: auto;
max-width: 100%;
margin-right: 20px;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.invoice-info {
flex: 1;
text-align: left; /* Align text to the right */
}
.invoice-info p {
margin: 0;
font-size: 16px;
color: #888;
}
.invoice-info h1 {
margin: 10px 0;
font-size: 24px;
}
/* ... Previous styles ... */
.invoice-amount {
display: flex;
align-items: center;
}
.invoice-amount h1 {
margin: 0;
font-size: 24px;
margin-right: 10px; /* Add margin to separate from "To USD" text */
}
.to-usd {
margin: 0;
font-size: 16px;
}
.copy-button {
background-color: transparent;
border: none;
cursor: pointer;
margin-left: 10px;
}
.copy-button img {
border-radius: 0px;
box-shadow: 0 0px 0px rgb(255, 255, 255);
width: 20px; /* Adjust the width as needed */
height: 20px; /* Adjust the height as needed */
}
/* ... Previous styles ... */
.address-input {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
margin-bottom: 10px;
padding-bottom: 5px;
}
.address-input input {
flex: 1;
border: none;
background-color: transparent;
outline: none;
padding: 0;
}
.transaction-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin-top: 20px;
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
overflow: hidden;
border: 1px solid #ddd;
}
.transaction-table th,
.transaction-table td {
padding: 10px;
text-align: center;
border: 1px solid #ddd;
font-size: 12px;
color: grey;
}
.highlighted-row {
background-color: rgba(144, 238, 144, 0.2);
border-radius: 10px;
}

2
src/css/utility.css Executable file

File diff suppressed because one or more lines are too long

1
src/css/utility.css.map Executable file

File diff suppressed because one or more lines are too long

1
src/img/crypto/black/$pac.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm-.065-28C9.342 4.001 4 9.347 4 15.94c.001 6.592 5.347 11.936 11.94 11.935 6.592-.002 11.936-5.347 11.935-11.94A11.937 11.937 0 0015.935 4zm-4.847 5.23a.123.123 0 01.125-.12h4.973a6.98 6.98 0 013.027.628c.18.088.357.186.528.292l-3.237 1.853h-1.689a.123.123 0 00-.12.126v.932l-3.607 2.086V9.23zM9.749 19.708l-2.162-2.184 7.12-4.108v2.662a.123.123 0 00.125.12h1.017l-6.093 3.51h-.007zm10.662-2.03c-1.044.872-2.477 1.308-4.299 1.308h-1.297a.123.123 0 00-.123.123v2.688l-1.81 1.042-1.69.977-.107.06v-4.455l5.603-3.224a2.056 2.056 0 001.297-.513 1.74 1.74 0 00.318-.432l3.578-2.071c.06.328.09.66.089.994.004 1.463-.516 2.63-1.56 3.503zm-1.92-3.019c.024-.153.036-.309.037-.464a2.417 2.417 0 00-.563-1.674A1.823 1.823 0 0017.15 12l4.973-2.871 2.182 2.183-5.814 3.347z"/></svg>

After

Width:  |  Height:  |  Size: 934 B

1
src/img/crypto/black/0xbtc.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm0-4.742c6.218 0 11.258-5.04 11.258-11.258 0-6.218-5.04-11.258-11.258-11.258C9.782 4.742 4.742 9.782 4.742 16c0 6.218 5.04 11.258 11.258 11.258zm0-.662c-5.852 0-10.596-4.744-10.596-10.596S10.148 5.404 16 5.404 26.596 10.148 26.596 16 21.852 26.596 16 26.596zm-1.91-2.464c.248-.102 1.218-.85 2.155-1.655a51.685 51.685 0 003.348-3.113c1.026-1.026 1.407-1.467 1.47-1.695.222-.801-2.205-9.606-2.699-9.795-.301-.116-2.993 2.123-5.377 4.467-1.398 1.374-1.785 1.831-1.815 2.13-.02.231.06.81.209 1.496.593 2.722 1.672 6.483 2.218 7.718.229.524.255.547.49.447z"/></svg>

After

Width:  |  Height:  |  Size: 725 B

1
src/img/crypto/black/1inch.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 0c8.837 0 16 7.163 16 16s-7.163 16-16 16S0 24.837 0 16 7.163 0 16 0zm-2.158 5.5h-.111c-.7.011-2.772.262-3.596 2.769-.255-.645-.49-1.584-.49-1.584s-.008.006-.02.019l-.055.055c-.29.303-1.301 1.533-.706 3.407a250.273 250.273 0 00-4.09-1.477l-.086-.028a.244.244 0 00-.019-.005c-.127-.019-.163.036-.163.036s-.037.056.072.148c.2.165 4.013 3.02 4.848 3.572-.181.663-.181.976 0 1.29.255.423.273.644.237.957-.037.313-.364 3.02-.436 3.352-.073.331-.835 1.51-.8 1.86.037.35.51 1.841.927 2.007.309.11 1.071.35 1.58.35.181 0 .345-.037.417-.11.309-.277.4-.332.618-.332h.054c.09 0 .2.018.327.018.29 0 .672-.055.944-.313.4-.405 1.09-.958 1.307-1.215.273-.35.418-.83.345-1.308-.054-.442.182-.829.454-1.215.345-.46.98-1.29.98-1.29 1.254.958 2.034 2.413 2.034 4.034 0 2.872-2.469 5.193-5.52 5.193a5.81 5.81 0 01-1.38-.166c1.399.497 2.579.663 3.541.663 2.052 0 3.142-.755 3.142-.755s-.382.497-1 1.068h.02c3.395-.479 5.047-3.315 5.047-3.315s-.127.921-.29 1.547c4.52-3.444 3.758-7.753 3.74-7.9.036.055.49.608.726.902.62-6.467-3.736-9.201-5.035-9.867l-.136-.068a3.867 3.867 0 00-.222-.101s.908.037 1.852.147c-2.124-1.694-4.14-2.191-5.774-2.191-2.251 0-3.776.939-3.867.994l.708-1.141s-.044-.005-.124-.006zm2.248 3.966c3.723.405 6.628 3.61 6.628 7.495a7.549 7.549 0 01-4.23 6.795c1.18-.92 2.087-2.21 2.487-3.665.018-.055.181-.147.29-.22.182-.093.363-.203.4-.35.072-.424.109-.866.109-1.308 0-.166-.164-.331-.327-.497-.091-.11-.236-.24-.236-.332a7.25 7.25 0 00-1.49-3.664c-.362-2.21-1.815-2.891-1.851-2.91l.023.036.049.08c.217.37.808 1.57.255 2.941-.672 1.64-2.397 1.381-2.542 1.4-.146 0-.709.736-1.417 2.099a1.967 1.967 0 00-.908-.055c.327-.921.817-2.228.908-2.339.037-.037.309-.11.49-.166.345-.092.509-.147.563-.22.037-.056.218-.48.4-.921.163 0 .58-.037.617-.056.037-.037.382-.939.382-1.05 0-.091-.709-1.878-.981-2.56a4.31 4.31 0 00.381-.533zm3.686 4.64a6.805 6.805 0 011.271 3.315c.018.148.164.295.309.442.127.11.272.258.272.35 0 .424-.036.847-.109 1.27-.018.056-.181.148-.308.222-.182.092-.345.184-.382.331l-.085.282a6.868 6.868 0 01-2.087 3.09l-.223.18.154-.168c1.582-1.8 2.31-4.635 1.043-6.901.182-.94.2-1.75.145-2.413zM14.783 7.11s.672 1.491-.036 2.578c-.727 1.086-1.435 1.289-1.435 1.289s.999.184 1.925-.497c.381.902.744 1.841.763 1.97l-.347.834-.147.353c-.171.406-.328.772-.36.82-.036.037-.29.11-.472.148-.309.092-.49.147-.563.202-.127.11-.708 1.731-.98 2.523a1.5 1.5 0 00-.89.645c.127-.092.526-.148.817-.184.254-.019 1.035.405 1.235 1.197v.036c.036.295-.055.571-.2.792-.073.092-.381.369-.6.571-.217.203-.453.405-.635.59-.072.073-.218.11-.436.11h-.544c.272-.368 1.071-1.216 1.343-1.4.327-.22.49-.442.29-.828-.199-.387-.725-.295-.725-.295s.308-.129.58-.129c-.344-.092-.78 0-.98.203-.218.202-.181.92-.272 1.38-.091.48-.4.719-.872 1.161-.254.24-.436.313-.58.313a6.189 6.189 0 01-.927-.24c-.181-.239-.454-1.03-.526-1.362.054-.184.272-.571.38-.792.219-.424.346-.663.382-.884.073-.313.309-2.247.4-3.057.236.313.563.829.49 1.16.527-.755.145-1.491-.036-1.786-.164-.295-.382-.884-.2-1.51.181-.626.835-2.357.835-2.357s.218.387.527.313c.308-.074 2.796-3.867 2.796-3.867zm-4.35 11.584s-.595 1.056-.649 1.202c-.054.164.036.455.27.437.235-.018.523-.364.523-.62 0-.327-.288-.29-.288-.29zm2.316.165c.146-.037.49.018.49.276 0 .24-.254.295-.435.46-.127.13-.382.405-.418.442l.001-.001.052-.095c.091-.206.096-.473.105-.617l.006-.06c.018-.13.054-.369.2-.405zm.853-7.464s-1.845 2.937-2.008 2.993c-.163.055-.325-.588-.325-.588-.344 1.34.579 1.524.687 1.102.507-.129 1.375-.68 1.719-1.065.343-.404.162-1.157-.47-1.285.162-.386.397-1.157.397-1.157zm1.02-3.162l-1.198 1.835h.016c.086-.006.482-.063.932-.593.412-.5.25-1.242.25-1.242z"/></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

1
src/img/crypto/black/2give.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm-.737-7.144v1.463H16V24.13h-1.463v.726h.726zm-7.337-8.03H7.2v3.652h.726v-1.463h.737v-1.463h-.737v-.726zm8.811 4.378v2.189h.726v-2.189h-.726zM16 23.393v.737h.737v-.737H16zm-7.337-.726v2.189h2.2v-2.189h-2.2zM7.2 15.363v.726h.737v-.726H7.2zm4.4-1.463v.737h.737V13.9H11.6zm4.4-.737v1.463h.737v-1.463H16zm-9.537-2.189v2.189h2.2v-2.189h-2.2zm6.6 13.882v1.463h.737v-1.463h-.737zm.737-11.693h-.726v1.463h.726V13.9h.737v-1.463H13.8v.726zm.737-1.452v.726h.726v-.726h-.726zm0 2.189v.726h.726V13.9h-.726zm-3.674 1.463v.726h2.2v-.726h-2.2zm2.937-2.926v-.726h.726v-.737H13.8V9.522h-2.2v.726h1.463v.726h-.737v.726H11.6v.726h-.726v-.715h-.748v-.726h.737v.715h.737v-.726h-.726V9.522H5v5.115h5.874V13.9h.726v-1.463h.737v.726h.737v-.726h.726zM9.4 13.9H5.737v-3.652H9.4V13.9zm.726 0v-1.463h.737V13.9h-.737zm2.937-2.2v-.715h.737v.715h-.737zm5.874 8.041v-.726h-1.474v-1.463h-.726v.726h-.726v-.726h.726v-2.2h-1.463v.737h-.748v1.463H13.8v.726h.737v-.726h.726v2.189H13.8v-.726h-.737v-1.463h-.726v-.726h-1.474V16.1h-.737v-.726H8.663v.726h-.737v.726h.737v.726H9.4v-.726h.737v.726H9.4v.726h.737v.726h.726v-.726h.737v-.726h.726v.726H11.6v.726h-.726v1.463h1.463v.737h-1.474v-.726h-.737v.726H8.663v-.726h-.726v.726H7.2v5.115h5.137V21.93h.726v2.2h1.474v-.726h.737V21.93h-.737v-.726H13.8v.726h-.726v-1.463h2.2v.726h.737v-1.452h1.452v.737h.737v-.737h.737zM11.6 25.582H7.937V21.93H11.6v3.652zm.737-5.841H11.6v-.726h.737v.726zm1.463 2.926h.737v.726H13.8v-.726zm5.137-13.145v1.452h.726V9.522h-.726zm-1.474 0h-.726v2.189H16v.726h.737v.726h.726v1.463h.737v-1.463h.737v1.474h.726V13.9h.737v-1.463h-1.463v-1.463h-1.474V9.522zm6.6 8.03H22.6v.726h-.737v.737h-.726v-2.189h.726v-.737h-.726v.726H20.4v.737h-.737v-1.463h-.726v1.463H18.2v.737l.737-.011h.726v1.463h2.2v.737h-2.2v.726h-.726v.726H18.2v.737h.737v.726H18.2v.737h.737v.726h.726v.726h-.726v.737H24.8V21.93h-.737v3.652H20.4V21.93h2.2v-2.915h.737v.726H24.8v-1.452h-.726v-.737h.726v-2.189h-.737v2.189zM18.2 20.478v.726h.737v-.726H18.2zm3.663-3.652v.726h.737v-.726h-.737zm1.474 3.652v.737H24.8v-.737h-1.463zm0-9.493v2.189h2.2v-2.189h-2.2zM20.4 13.9v.737h.737V13.9H20.4zm-2.937 1.463v.726h.737v-.726h-.737zm5.137 0v.726h.737v-.726H22.6zm-1.463 7.304v2.189h2.2v-2.189h-2.2zm-.737-7.304v.726h.737v-.726H20.4zm-5.137-4.389v.737H16v-.737h-.737zM20.4 9.522v.726h1.463v.726h-.737v.726H20.4v-.726h-.737v.737h.737v.715h.737v.726h.737v1.463H27V9.522h-6.6zm5.863 4.378H22.6v-3.652h3.663V13.9zM9.851 8.235c.506.341 1.078.407 1.529.429.385.022 1.034.022 1.716.022 1.265 0 2.75.022 2.904.022.407.011 1.65.011 2.75.011.682 0 1.32-.011 1.716-.022.451-.022 1.023-.099 1.529-.429.638-.429.957-1.133.957-2.09 0-.77-.319-1.232-.583-1.496-.715-.693-1.815-.649-2.178-.638h-.044c-.22 0-1.012.121-1.947.649-.825.462-1.54 1.122-2.123 1.947l-.066.165-.055-.088c-.616-.924-1.419-1.551-2.31-2.057-.924-.528-1.716-.638-1.936-.638h-.044c-.363-.011-1.463-.055-2.178.638-.484.462-.583 1.067-.583 1.496-.011.946.308 1.65.946 2.079zm8.888-2.464c.781-.451 1.375-.517 1.419-.517h.077c.627-.022 1.067.077 1.298.297.143.143.22.341.22.627 0 1.045-.495 1.276-1.342 1.32-.715.033-2.376.022-3.454.011a5.168 5.168 0 011.782-1.738zm-8.426-.253c.209-.198.583-.297 1.122-.297h.264c.044 0 .638.066 1.419.517.704.407 1.309.99 1.793 1.738-1.089.011-2.75.022-3.465-.011-.847-.044-1.342-.275-1.342-1.32 0-.286.066-.484.209-.627zm7.15 19.338h-.726v1.463h.737v-1.463h.726v-.726h-.737v.726z"/></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

1
src/img/crypto/black/aave.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 0c8.837 0 16 7.163 16 16s-7.163 16-16 16S0 24.837 0 16 7.163 0 16 0zm.243 7h-.473c-.592 0-1.039.343-1.341 1.042l-2.327 5.896h-1.761c-.528.002-.956.448-.96 1v.014c.004.553.432.999.96 1.001h.946l-2.221 5.621a1.235 1.235 0 00-.066.384c0 .315.092.562.263.754.17.192.407.288.71.288a.933.933 0 00.552-.192c.17-.123.289-.302.38-.507l2.446-6.348h1.696c.527-.002.955-.449.96-1.001v-.027c-.005-.553-.433-1-.96-1.001h-.907l1.866-4.867L21.093 22.3c.092.205.21.384.381.507.161.122.354.19.553.192.302 0 .539-.096.71-.288.17-.192.262-.439.262-.754a.944.944 0 00-.065-.384l-5.35-13.532C17.28 7.342 16.834 7 16.243 7z"/></svg>

After

Width:  |  Height:  |  Size: 705 B

1
src/img/crypto/black/abt.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path fill-rule="evenodd" d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zM6.5 10.487v11.026L16 27l9.5-5.487V10.487L16 5l-9.5 5.487zm.912 9.97v-8.913l5.743 3.323-1.933 3.385-3.81 2.205zm.457.791l3.664-2.12 4.038 2.313v4.256l-7.702-4.449zm16.719-9.673v8.85l-3.76-2.175-1.932-3.382 5.692-3.293zm-.43-.808l-5.715 3.307-1.96-3.431V6.334l7.675 4.433zm-6.047 4.555l1.153 2.023L16.939 16l1.172-.678zm-.453-.794l-1.175.68v-2.74l1.175 2.06zm-4.864 2.815l1.151-2.02 1.17.677-2.32 1.343zm-.346 1.256l3.123-1.807v3.595L12.448 18.6zm-4.58-7.847l7.703-4.449v4.334l-1.962 3.436-5.74-3.321zm16.29 10.481l-7.675 4.433V21.47l4.04-2.34 3.635 2.103zm-4.548-2.632l-3.127 1.813v-3.622l3.127 1.81zm-5.212-4.071l1.173-2.057v2.735l-1.173-.678z"/></svg>

After

Width:  |  Height:  |  Size: 838 B

1
src/img/crypto/black/act.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zM13.77 6.5a.87.87 0 00-.759.444L6.105 19.263a.87.87 0 000 .85l2.21 3.942a.87.87 0 00.758.445h13.854a.87.87 0 00.759-.445l2.209-3.942a.87.87 0 000-.85L18.989 6.944a.87.87 0 00-.759-.444h-4.46zM16 11.401l4.653 8.287h-9.306L16 11.401z"/></svg>

After

Width:  |  Height:  |  Size: 382 B

1
src/img/crypto/black/actn.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zM4.406 21.711a5.525 5.525 0 00-.406.773c0 .036.144.036.295.036.34-.03.673-.103.994-.218l.441-.11a7.68 7.68 0 001.325-.738l.809-.662c.392-.318.75-.676 1.068-1.068l.883-1.253c.627-.845 1.325-1.25 2.136-1.214a3 3 0 001.325-.367l2.282-1.472a5.44 5.44 0 00.663-.48 3.12 3.12 0 00-.406-.736l-.441-.735c-.478-.773-.478-.811-.036-1.62l.036-.11a6.22 6.22 0 00.37-.737 4.414 4.414 0 00-.15-1.078 2.136 2.136 0 00-.292.48c-.406.845-.663 1.325-.701 1.325-.11 0-.036-1.032.185-1.656l.993-3.12c.257-.921.295-.921.552 0l1.469 4.601c.187.626.336.737.96.737h1.03c.808-.039 1.322.331 1.73 1.214.222.39.495.75.811 1.068l5.117 5.309c.162.201.348.383.552.542v-.036c-.126-.225-.26-.446-.403-.662l-3.792-5.448c-.29-.416-.611-.81-.96-1.178l-1.176-1.25a1.853 1.853 0 00-1.253-.553h-.293c-.921 0-1.805-.662-2.172-1.584l-1.62-4.013A1.982 1.982 0 0015.964 5c-.191.197-.353.42-.48.662l-3.749 5.744a.703.703 0 01-.993.292h-.039c-.372-.22-.739-.11-.96.296L4.406 21.71z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
src/img/crypto/black/ada.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm-.275-25.94c-.39.152-.49.707-.186.988.287.293.847.19.995-.193.255-.471-.33-1.042-.81-.796zm-5.155.546c-.405.106-.45.734-.057.884.297.16.718-.089.687-.427.03-.313-.339-.575-.63-.457zm10.558.893c.31.078.54-.17.612-.44-.05-.317-.362-.622-.701-.46-.438.142-.366.846.089.9zm-9.385 1.265c-.456.23-.519.914-.105 1.212.428.38 1.186.054 1.211-.507.075-.557-.62-1.008-1.106-.705zm7.43.322c-.271.536.276 1.15.853 1.044.435-.142.736-.659.491-1.076-.247-.536-1.127-.519-1.344.032zm-4.069 1.013c-.026.386.255.702.588.863.218.013.455.054.655-.056.438-.19.654-.762.411-1.178-.13-.3-.46-.428-.763-.488-.458.033-.896.385-.891.859zm-7.666.69c-.388.175-.442.766-.1 1.012.322.262.884.095.976-.316.169-.475-.431-.966-.876-.697zm16.462-.002c-.388.234-.345.858.067 1.04.374.22.913-.102.887-.529.045-.468-.577-.799-.954-.51zm-6.64.851c-.776.232-1.236 1.158-.92 1.898.278.827 1.377 1.211 2.13.758.725-.383.974-1.4.506-2.067-.354-.546-1.094-.81-1.716-.589zm-3.653.073c-.735.323-1.073 1.276-.692 1.978.34.725 1.33 1.023 2.032.63.701-.349 1.004-1.29.612-1.966-.333-.694-1.262-.963-1.952-.642zM9.95 12.94c-.101.514.365 1.036.898.99.484.003.837-.436.867-.885a.978.978 0 00-.87-.857c-.423.03-.842.315-.895.752zm10.802-.656c-.587.272-.63 1.172-.065 1.492.544.384 1.384-.077 1.347-.732.024-.618-.735-1.073-1.282-.76zm-8.63 2.307c-.868.206-1.376 1.256-.958 2.039.365.854 1.626 1.106 2.31.48.534-.427.674-1.236.331-1.818-.314-.578-1.045-.874-1.684-.701zm6.927-.003c-.874.235-1.336 1.325-.877 2.096.38.746 1.447.996 2.136.52.657-.411.868-1.362.426-1.999-.334-.557-1.064-.792-1.685-.617zm-11.04.726c-.53.148-.687.904-.262 1.243.363.362 1.066.18 1.203-.31.223-.539-.389-1.138-.941-.933zm14.969.782c.092.21.203.43.42.538.464.251 1.119-.112 1.084-.647.03-.406-.338-.706-.716-.765a.836.836 0 00-.788.874zM5.294 15.58c-.275.123-.394.49-.194.729.226.343.843.185.86-.226.077-.363-.334-.646-.666-.503zm20.949-.009c-.39.205-.237.912.235.87.336.05.624-.353.467-.647-.093-.269-.468-.386-.702-.223zm-12.317 1.973c-.654.14-1.158.751-1.156 1.409-.023.687.52 1.343 1.212 1.453.895.206 1.82-.587 1.763-1.482-.005-.886-.945-1.603-1.82-1.38zm3.462-.001c-.526.128-.972.555-1.088 1.08-.23.787.378 1.678 1.203 1.783.876.174 1.773-.593 1.726-1.471.014-.906-.954-1.636-1.84-1.392zm-6.676.545c-.663.066-1.013.943-.545 1.422.4.5 1.304.334 1.486-.278.249-.573-.327-1.247-.94-1.144zm10.154.027c-.661.207-.772 1.2-.165 1.536.535.376 1.365-.068 1.343-.711.042-.585-.63-1.05-1.178-.825zm2.838 2.8c.145.398.75.493 1.017.16.197-.179.148-.457.119-.69-.141-.144-.296-.315-.517-.311-.444-.073-.833.448-.619.841zm-16.268-.732c-.395.198-.409.817-.027 1.034.356.24.896-.001.945-.423.094-.477-.503-.882-.918-.61zm8.193.883c-.654.207-.752 1.193-.163 1.528.531.39 1.387-.06 1.346-.71.052-.588-.64-1.053-1.183-.818zm-3.794.871c-.326.12-.459.474-.465.791.112.291.338.598.685.605.42.062.834-.294.82-.712.042-.51-.578-.923-1.04-.684zm7.686.008c-.464.233-.516.937-.088 1.23.443.374 1.207.01 1.195-.56.045-.544-.631-.96-1.107-.67zm1.337 3.25c.217.366.85.236.891-.19.058-.316-.234-.52-.51-.575-.344.072-.593.451-.381.766zm-10.611-.273c.03.359.428.67.77.443.381-.2.252-.845-.183-.875-.299-.065-.503.183-.587.432zm5.12.287c-.153.373.213.824.618.777.218.005.387-.148.518-.3.025-.103.051-.207.08-.31-.054-.198-.116-.43-.328-.52-.32-.196-.805-.016-.889.353z"/></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

1
src/img/crypto/black/add.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm8.984-14.369h-4.928l-.88-2.64h5.8a.748.748 0 100-1.496H18.7l-2.517-7.673a1.074 1.074 0 00-2.12-.07l-6.02 18.303c-.016.1-.016.2 0 .3a1.012 1.012 0 001.989.246l5.051-15.4 1.443 4.294h-1.25a.748.748 0 100 1.496h1.76l.88 2.64h-2.64a.748.748 0 100 1.496h3.16l1.425 4.224h-7.559a1.056 1.056 0 100 2.112h8.941c.554 0 1.003-.449 1.003-1.003a1.03 1.03 0 00-.097-.44l-1.61-4.893h4.4a.748.748 0 100-1.496h.044z"/></svg>

After

Width:  |  Height:  |  Size: 574 B

1
src/img/crypto/black/adx.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill-rule="evenodd" d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zM11.587 8.602L9 11.36l4.36 4.614L9 20.68l2.587 2.717L16 18.792l4.305 4.604L23 20.603l-4.396-4.604L23 11.36l-2.695-2.757L16 13.208l-4.413-4.606zm.355-.376l2.126 2.265 1.914-2.114 1.914 2.114 2.126-2.265L15.982 4l-4.04 4.226zm0 15.548L15.982 28l4.04-4.226-2.126-2.265-1.914 2.114-1.914-2.114-2.126 2.265z"/></svg>

After

Width:  |  Height:  |  Size: 473 B

1
src/img/crypto/black/ae.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path fill-rule="evenodd" d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zM9.752 11c-2.473.174-4.591 2.228-4.752 4.621v.785c.17 2.398 2.317 4.428 4.787 4.594h.803c1.96-.172 3.608-1.415 4.796-2.862-.29-.425-.583-.849-.884-1.266-.764 1.128-1.76 2.192-3.102 2.66-1.208.438-2.61.157-3.615-.596-1.342-.95-1.83-2.793-1.23-4.279.682-1.804 2.97-2.866 4.843-2.187 1.515.551 2.45 1.915 3.366 3.128 1.064 1.372 1.944 2.913 3.315 4.036.944.802 2.156 1.266 3.403 1.366h.746c2.026-.18 3.879-1.534 4.515-3.417a60.387 60.387 0 00-1.389.006c-.908 1.854-3.493 2.751-5.341 1.654-2.557-1.517-3.661-4.394-5.67-6.432-.968-.99-2.274-1.677-3.687-1.811h-.904zm11.68 0c-1.974.183-3.61 1.453-4.783 2.921.275.407.559.809.845 1.207.743-1.075 1.707-2.081 2.987-2.54 1.606-.61 3.615-.035 4.565 1.37.39.538.54 1.189.654 1.825-1.624.01-3.247 0-4.873.004.002.36.002.717 0 1.077 2.057-.002 4.116.01 6.173-.009v-1.23c-.205-2.397-2.325-4.468-4.818-4.625h-.75z"/></svg>

After

Width:  |  Height:  |  Size: 1019 B

1
src/img/crypto/black/aeon.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm10.965-17.29c-.328-2.964-5.51-4.798-11.57-4.095-6.06.702-10.706 3.675-10.378 6.64.329 2.964 5.507 4.797 11.57 4.095 6.065-.703 10.707-3.676 10.378-6.64zm-6.34 1.484c-.614.438-1.509.654-2.684.659l-1.141.004-.035.163a.434.434 0 00-.017.11c-.005.023-.005.045-.005.063 0 .252.117.437.346.56.23.129.57.19 1.016.19.423 0 .83-.048 1.214-.136.38-.089.748-.221 1.098-.398l-.29 1.555c-.436.106-.855.19-1.27.243a8.807 8.807 0 01-1.206.089c-.553 0-1.011-.067-1.379-.208-.38-.146-.804-.464-1.015-.919a4.641 4.641 0 01-1.34.892 3.684 3.684 0 01-1.453.296c-.63.005-1.128-.15-1.482-.455-.359-.304-.536-.729-.54-1.263-.005-.822.302-1.445.912-1.878.613-.437 1.508-.653 2.684-.658l1.14-.004.035-.164a.434.434 0 00.018-.11c.004-.022.004-.044.004-.062 0-.252-.117-.437-.346-.561-.229-.128-.57-.19-1.016-.19-.423 0-.83.049-1.214.137-.38.088-.748.22-1.098.398l.29-1.555c.436-.106.855-.19 1.27-.243a8.807 8.807 0 011.206-.089c.554 0 1.012.067 1.38.208.38.146.803.464 1.015.919a4.641 4.641 0 011.34-.893 3.684 3.684 0 011.452-.296c.631-.004 1.128.15 1.482.455.36.305.536.73.54 1.264.005.817-.297 1.444-.911 1.877zm-6.626.128c-.497 0-.873.084-1.133.243-.25.155-.376.39-.376.698 0 .23.078.416.225.548.151.133.363.199.627.199.41 0 .752-.128 1.024-.38.273-.256.458-.614.55-1.073l.042-.235h-.96zm5.264-2.169c-.151-.132-.363-.198-.626-.198-.411 0-.753.128-1.025.38-.272.256-.458.614-.549 1.073l-.043.234.96-.004c.497 0 .873-.084 1.132-.243.25-.155.376-.389.376-.698 0-.23-.073-.411-.225-.544zm-2.74 7.55c-.877.102-1.746.15-2.589.15-2.006 0-3.881-.282-5.442-.835a8.81 8.81 0 01-1.84-.883c-.213 1.118-.07 2.103.479 2.836 1.577 2.107 5.99 1.436 10.356-1.4-.32.048-.64.092-.964.132zm-1.024-11.397c2.96-.345 5.813-.102 8.03.684a8.81 8.81 0 011.842.884c.211-1.118.069-2.103-.48-2.836-1.578-2.107-5.99-1.436-10.356 1.4.32-.053.644-.097.964-.132zm-3.22 13.96a9.094 9.094 0 01-1.76.242c.446 1.18 1.142 2.006 2.062 2.315 2.222.747 5.096-1.7 7.132-5.752-.48.133-.977.252-1.478.354-1.989 1.405-4.063 2.399-5.956 2.84zm7.598-16.554a9.044 9.044 0 011.76-.234c-.442-1.18-1.133-2.01-2.054-2.323-2.217-.756-5.104 1.678-7.153 5.716.48-.132.977-.247 1.482-.344 1.989-1.4 4.068-2.382 5.965-2.815z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

1
src/img/crypto/black/aeur.svg Executable file
View File

@ -0,0 +1 @@
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm-.048-13.014a7.144 7.144 0 00.093 0 .055.055 0 01.004.014.049.049 0 11-.097-.014zm-6.014-3.493a6.993 6.993 0 006.055 10.493 7.002 7.002 0 006.993-6.993 6.96 6.96 0 00-.94-3.503 6.993 6.993 0 10-12.11.003zM16.048 12a7.138 7.138 0 00-.097 0 .049.049 0 01.049-.05.055.055 0 01.049.05z"/></svg>

After

Width:  |  Height:  |  Size: 456 B

1
src/img/crypto/black/agi.svg Executable file
View File

@ -0,0 +1 @@
<svg height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm1.144-25.576c.502.483.956 1.01 1.356 1.576a5.047 5.047 0 01-.125 5.273.627.627 0 00.063.727c.214.29.624.37.937.182 1.188-.97 1.25-3.03 1.313-3.455a4.497 4.497 0 00-.188-1.272 6.463 6.463 0 00-.5-1.152 3.709 3.709 0 00-.75-.97 5.63 5.63 0 00-1.875-1.272.289.289 0 00-.313 0 .28.28 0 00.082.363zM15.3 25.006c-.51-.481-.97-1.01-1.375-1.576a5.047 5.047 0 01.125-5.272.539.539 0 000-.728.714.714 0 00-.938-.182c-1.187.97-1.25 3.03-1.312 3.455 0 .43.064.86.188 1.273.128.398.295.784.5 1.151.193.361.446.689.75.97a5.63 5.63 0 001.875 1.273c.062.06.187 0 .25-.06s.062-.183-.063-.304zm5.394-5a5.473 5.473 0 00-1.313-3.151 10.816 10.816 0 00-2.625-1.94 14.466 14.466 0 01-2.375-1.642 4.032 4.032 0 01-1.187-2.121 4.243 4.243 0 01.306-2.48 6.692 6.692 0 011.756-2.242.26.26 0 00.063-.303.242.242 0 00-.375-.06 5.577 5.577 0 00-2.438 2.06 5.01 5.01 0 00-.881 3.273 5.25 5.25 0 00.438 1.697 6 6 0 001 1.455 10.78 10.78 0 002.687 1.878c.848.44 1.645.969 2.375 1.576a3.603 3.603 0 011.188 2.182c.176.879.066 1.79-.313 2.606a6.13 6.13 0 01-1.813 2.182.207.207 0 00-.063.303c.035.064.1.11.173.121s.149-.01.203-.06a7.801 7.801 0 002.375-2.122c.62-.958.906-2.084.819-3.212z"/><path d="M17.144 6.424a.28.28 0 01-.081-.363.289.289 0 01.312 0 5.63 5.63 0 011.875 1.272c.303.281.557.609.75.97.204.368.371.753.5 1.152.123.413.187.842.188 1.272-.063.425-.125 2.485-1.313 3.455a.714.714 0 01-.938-.182.627.627 0 01-.062-.727A5.047 5.047 0 0018.5 8c-.4-.566-.854-1.093-1.356-1.576zM15.3 25.006c.125.121.125.242.063.303s-.188.121-.25.06a5.63 5.63 0 01-1.875-1.272 3.709 3.709 0 01-.75-.97 6.463 6.463 0 01-.5-1.151 4.482 4.482 0 01-.188-1.273c.063-.424.125-2.485 1.313-3.455a.714.714 0 01.937.182.539.539 0 010 .728 5.047 5.047 0 00-.125 5.272c.405.567.866 1.095 1.375 1.576z" fill-opacity=".5"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

1
src/img/crypto/black/agrs.svg Executable file
View File

@ -0,0 +1 @@
<svg height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M16 32C7.163 32 0 24.837 0 16S7.163 0 16 0s16 7.163 16 16-7.163 16-16 16zm3.755-14.666C22.001 13.815 23.75 8 23.75 8l-3.745.849-1.371 4.85c-.129-3.636-2.622-4.967-2.622-4.967-1.997-.973-3.777-.545-5.06.124-1.588.826-2.743 2.266-3.296 3.924-.786 2.359-.69 5.006-.586 6.204.042.562.166 1.115.37 1.643 1.378 3.573 5.195 3.37 5.195 3.37 3.497-.124 5.622-4.242 5.622-4.242l1.002 3.028c.898 1.519 2.887.95 3.296.865.072-.016.136-.024.209-.04L25 23.267v-.973c-4.868.132-5.245-4.959-5.245-4.959zm-4.739 3.659a2.369 2.369 0 01-1.098.638c-.907.226-1.604-.155-2.085-.622a3.937 3.937 0 01-1.059-1.978c-.882-4.99.337-7.177 1.147-8.182a2.258 2.258 0 011.868-.864c3.144.164 3.85 6.742 3.85 6.742-.89 2.335-2.037 3.69-2.623 4.266z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 835 B

Some files were not shown because too many files have changed in this diff Show More