You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kycnot.me/kycnot.py

417 lines
17 KiB

# /path/to/server.py
from jinja2 import Environment, FileSystemLoader, Template
from datetime import timedelta, datetime
from urllib.parse import unquote
from sanic.response import redirect
from sanic.response import json as sjson, text
from sanic.response import html
from sanic import Sanic
from sanic import response
from dateutil import parser
from random import randrange, randint, shuffle
import json
import os.path
import qrcode
import httpx
import os
import gdshortener
import re
import time
from automatedChecks import get_exchange_score
from utils.ratesApi import getAllRates
# Generate QR Codes for donation addresses
from dotenv import load_dotenv
import qrcode
load_dotenv()
xmrDonations = os.getenv("XMR_DONATION_ADDRESS")
btcDonations = os.getenv("BTC_DONATION_ADDRESS")
btcqr = qrcode.make(btcDonations)
btcqr.save("static/img/qrcodes/btc.png")
xmrqr = qrcode.make(xmrDonations)
xmrqr.save("static/img/qrcodes/xmr.png")
FIRST_RUN=datetime.utcnow()
base_dir = os.path.abspath(os.path.dirname(__name__))
static_dir = os.path.join(base_dir, 'static')
templates_dir = os.path.join(base_dir, 'templates')
data_dir = os.path.join(base_dir, 'data')
env = Environment(loader=FileSystemLoader(templates_dir), autoescape=True)
app = Sanic(__name__)
app.static('/static', static_dir)
def keep_dupes(iterable, times):
seen = []
dupes = []
result = []
for item in iterable:
if item in seen and item not in dupes:
if 'times' not in item:
item['times'] = 1
item['times'] += 1
if item['times'] == times:
result.append(item)
dupes.append(item)
else:
seen.append(item)
return result
# filename = ""
@app.route("/", name="root")
@app.route("/index", name="index")
async def index(request):
oneweekago = datetime.today() - timedelta(days=7)
with open(f'{data_dir}/changes.html', 'r') as f:
cf = f.read()
d = re.search('<h1>(.+?)</h1>', cf)
last_update = d.group(1)
if(request.args):
args = list(request.args.keys())
template = env.get_template('index.html')
f = open(f'{data_dir}/exchanges.json')
data = json.load(f)
exchanges = []
for exchange in data['exchanges']:
exchange['listing-date'] = parser.parse(exchange['listing-date'])
if isinstance(exchange['url'], list):
exchange['url'] = exchange['url'][randint(0, len(exchange['url'])-1)]
for arg in args:
if exchange[arg]:
exchanges.append(exchange)
if len(args) > 1:
exchanges = keep_dupes(exchanges, len(args))
return html(template.render(date=oneweekago, data=exchanges,
title="exchange",
active=0,
last_update=last_update,
filters=args,
subtitle="Find best <strong>NON-KYC</strong> online services."))
else:
template = env.get_template('index.html')
f = open(f'{data_dir}/exchanges.json')
data = json.load(f)
data['exchanges'] = sorted(data['exchanges'], key=lambda k: k['score'], reverse=True)
# Randomly sort exchanges within they rating range
exchangesSorted = []
for s in range(11):
tempRange = []
for e in data['exchanges']:
if e['score'] == s:
tempRange.append(e)
if len(tempRange) > 0:
shuffle(tempRange)
exchangesSorted = tempRange + exchangesSorted
data['exchanges'] = exchangesSorted
for e in data['exchanges']:
e['listing-date'] = parser.parse(e['listing-date'])
if isinstance(e['url'], list):
e['url'] = e['url'][randint(0, len(e['url'])-1)]
return html(template.render(date=oneweekago, data=data['exchanges'],
title="exchange",
last_update=last_update,
active=0,
subtitle="Find best <strong>NON-KYC</strong> online services."))
@app.route("/services", name="services")
async def services(request):
oneweekago = datetime.today() - timedelta(days=7)
if(request.args):
args = list(request.args.keys())
if 'type' in request.args:
args.remove('type')
_type = request.args['type'][0]
else:
_type = False
template = env.get_template('index.html')
f = open(f'{data_dir}/services.json')
data = json.load(f)
services = {}
if len(args) > 0:
for key in data['services'].keys():
services = services | {key:[]}
for service in data['services'][key]:
# Treat the info
service['listing-date'] = parser.parse(service['listing-date'])
if isinstance(service['url'], list):
service['url'] = service['url'][randint(0, len(service['url'])-1)]
# For each filter parameter
for arg in args:
# If the service has it
if service[arg]:
# If there is no type filter, we just add it
if not _type:
services[key].append(service)
else:
# If there is a type filter we check if the service is from that type
if _type == key:
services[key].append(service)
else:
for key in data['services'].keys():
services = services | {key:[]}
for service in data['services'][key]:
service['listing-date'] = parser.parse(service['listing-date'])
if isinstance(service['url'], list):
service['url'] = service['url'][randint(0, len(service['url'])-1)]
if not _type:
services[key].append(service)
else:
# If there is a type filter we check if the service is from that type
if _type == key:
services[key].append(service)
if not _type: _type="Type"
for key in data['services'].keys():
shuffle(data['services'][key])
services = {k:v for k,v in services.items() if v}
return html(template.render(date=oneweekago, data=services,
title="service",
active=1,
filters=list(request.args.keys()),
_type=_type,
subtitle="Find best <strong>NON-KYC</strong> online services."))
template = env.get_template('index.html')
f = open(f'{data_dir}/services.json')
data = json.load(f)
for key in data['services'].keys():
shuffle(data['services'][key])
#data['services'] = sorted(data['services'], key=lambda k: k['name'], reverse=False)
for s in data['services'][key]:
s['listing-date'] = parser.parse(s['listing-date'])
# Remove empty values (i.e. EML: [])
data['services'] = {k:v for k,v in data['services'].items() if v}
return html(template.render(date=oneweekago, data=data['services'],
title="service",
active=1,
_type="Type",
subtitle="Find best <strong>NON-KYC</strong> online services."))
@app.route("/about", name="about")
async def about(request):
oneweekago = datetime.today() - timedelta(days=7)
template = env.get_template('about.html')
donations = {
"xmr": xmrDonations,
"nano": "nano_3txph9t1dwr778143me6ifaeo4ddyjcwfs4wymca5dtfdwdqjmff8nfhixgj",
"ltc": "MMSW3AnzHbxnmVeXzGjnNgHf6h62qpR9VA",
"btc": btcDonations
}
return html(template.render(date=oneweekago, title="KYC? Not me!",
subtitle="About KYCNOT.ME",
active=2,
support=donations))
@app.route("/exchange/<name>")
async def exchange(request, name=None):
oneweekago = datetime.today() - timedelta(days=7)
if(name):
f = open(f'{data_dir}/exchanges.json')
data = json.load(f)
for exchange in data['exchanges']:
if ''.join(exchange['name'].split()).lower() == name:
template = env.get_template('exchange.html')
if isinstance(exchange['url'], list):
exchange['url'] = exchange['url'][randint(0, len(exchange['url'])-1)]
return html(template.render(date=oneweekago, status=200, item=exchange, title="KYC? Not me!", active=0))
return(f"{name} does not exist")
@app.route("/service/<name>")
async def service(request, name=None):
oneweekago = datetime.today() - timedelta(days=7)
if(name):
template = env.get_template('services.html')
f = open(f'{data_dir}/services.json')
data = json.load(f)
for key in data['services'].keys():
for service in data['services'][key]:
if service['name'].replace(' ', '').lower() == name:
tpinfo = {"score": False}
template = env.get_template('service.html')
return html(template.render(date=oneweekago, item=service, tpinfo=tpinfo, active=1))
return(f"{name} does not exist")
@app.route("/scores", name="scores")
async def key(request, name=None):
with open("data/score_summary.txt") as f:
data = f.read()
return text(data)
@app.route("/requests", name="requests_status")
async def key(request, name=None):
with open("data/status.txt") as f:
data = f.read()
return text(data)
@app.route("/key", name="key")
@app.route("/pgp", name="pgp")
async def key(request, name=None):
key = """
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEYwdv5BYJKwYBBAHaRw8BAQdAAw6xG7G1lMkQi+ph/eCGrSPmretZ1eJ3X6It
C+o4jH20F1BsdWphIDxwbHVqYUBreWNub3QubWU+iJAEExYIADgWIQQFUj1t5ZFX
WwpaRM4VlC7bg/WdVwUCYwdv5AIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK
CRAVlC7bg/WdV/oxAQCuLgpICVFf+Qf4ywF3ETYls+ah1ILY4rzax66hGo9nHQD7
BPLc6ahF9acCdT1ZpH+Xv6IvKg7Aj+tK7C5p0I9RFQ24OARjB2/kEgorBgEEAZdV
AQUBAQdAZTc270z91hRjhFNMe8LTmytIRYul93gn2xG8cMco9jsDAQgHiHgEGBYI
ACAWIQQFUj1t5ZFXWwpaRM4VlC7bg/WdVwUCYwdv5AIbDAAKCRAVlC7bg/WdVw96
AP9IBOUCrd3oeqf4lJERrLikGSt/DsqMb54akDMHcU9AfgEA57F9XgVXt1w3RgfR
IkqtmcqulMiQtws0Q3jBTJsKewk=
=J+yt
-----END PGP PUBLIC KEY BLOCK-----
This is my PGP key.
It is also uploaded to Codeberg here, please compare it: https://codeberg.org/pluja/kycnot.me/src/branch/ui-redesign/data
If you don't know how to use PGP, you can easily verify any signed messages here: https://pgptool.org/
"""
return text(key)
@app.route("/changelog")
async def changelog(request, name=None):
with open(f'{data_dir}/changes.html', "r") as f:
changes = f.read()
return html(changes)
def set_default(obj):
if isinstance(obj, set):
return list(obj)
raise TypeError
@app.route("/rates", name="rates", methods=['POST', 'GET'])
async def rates(request):
if(request.args):
args = request.args
rates = await getAllRates(args['from_ticker'][0], args['to_ticker'][0], args['from_amount'][0])
#rates = compareRates(args['from_ticker'][0], args['to_ticker'][0], float(args['from_amount'][0]))
#f = open(f'{data_dir}/exchanges.json')
#data = json.load(f)
#exchanges = data['exchanges']
exchanges = {}
template = env.get_template('rates.html')
return(html(template.render(rates=rates,
exchanges=exchanges,
from_amount=args['from_amount'][0],
from_ticker=args['from_ticker'][0],
to_ticker=args['to_ticker'][0])))
else:
template = env.get_template('rates.html')
return html(template.render(rates=False, exchanges=False))
@app.route("/generator", name="generator", methods=['POST', 'GET'])
async def generator(request):
if(request.args):
args = request.args
if len(args) > 1:
if 'generate' in args:
if 'Exchange' in args['type']:
item_json = {
"name": args['name'][0],
"verified": False,
"btc": args['btc'][0],
"xmr": args['xmr'][0],
"lnn": args['lnn'][0],
"cash": args['cash'][0],
"p2p": args['p2p'][0],
"tor-only": args['tor-only'][0],
"tor": args['tor'][0],
"refunds": args['refunds'][0],
"open-source": args['open-source'][0],
"custodial": args['custodial'][0],
"javascript": args['javascript'][0],
"no-registration": args['no-registration'][0],
"personal-info": args['personal-info'][0],
"buy": args['buy'][0],
"app": args['app'][0],
"exchange": args['exchange'][0],
"meta-description": False,
"short-description": args['short-d'][0],
"long-description": args['large-d'][0],
"comments": False,
"kyc-check": False,
"kyc-type": int(args['kyc-type'][0]),
"score": False,
"suspicious-tos": False,
"tor-onion": args['tor-url'][0],
"url": args['url'][0],
"referral": False,
"tos-urls": [
args['tos-url'][0]
],
"third-party-connections": False,
"score-boost": 0,
"listing-date": str(datetime.today().strftime("%Y-%m-%d")),
"api": args['api'][0],
"api-url": args['api-url'][0],
"status": 200
}
item_json['score'] = get_exchange_score(item_json)
else:
item_json = {
"name": args['name'][0],
"url": args['url'][0],
"referral_url": False,
"tos-url": args['tos-url'][0],
"short-description": args['short-d'][0],
"long-description": args['large-d'][0],
"meta-description": "",
"btc": args['btc'][0],
"xmr": args['xmr'][0],
"lnn": args['lnn'][0],
"cash": args['cash'][0],
"app": args['app'][0],
"comments": False,
"verified": False,
"no-registration": args['no-registration'][0],
"personal-info": args['personal-info'][0],
"tor": args['tor'][0],
"tor-only": args['tor-only'][0],
"tor-onion": args['tor-url'][0],
"open-source": args['open-source'][0],
"tags": args['tags'],
"javascript": args['javascript'][0],
"listing-date": str(datetime.today().strftime("%Y-%m-%d")),
"api": False
}
print(str(item_json).replace("False", 'false').replace("True", "true").replace("'", '"').replace('"false"', 'false').replace('"true"', "true"))
jsonString = str(item_json).replace("False", 'false').replace("True", "true").replace("'", '"').replace('"false"', 'false').replace('"true"', "true")
return sjson(json.loads(jsonString))
else:
s = gdshortener.ISGDShortener()
name = args['name'][0].replace(" ", "_")
rurl = request.url.split('/')[3]
baseurl = "https://kycnot.me/"
if "Exchange" in args['type']:
shurl = s.shorten(f"{baseurl}{str(rurl)}&type=Exchange&generate=True", custom_url = f"{randint(0,999999999999)}_kycnot")[0]
else:
shurl = s.shorten(f"{baseurl}{str(rurl)}&type=Service&generate=True", custom_url = f"{randint(0,999999999999)}_kycnot")[0]
return(html(f"Copy the following URL to fill the request: <b><pre>{shurl}</pre></b>"))
else:
_type = args['type'][0]
else:
_type='Exchange'
template = env.get_template('generator.html')
return(html(template.render(_type=_type)))