from lxml import html # Todo: move all requests to using requests instead of urllib3 import urllib.request, urllib.error import requests from lxml import etree from random import choice import json import time import os.path from PIL import Image, ExifTags, ImageFile from datetime import datetime from binascii import crc32 from math import floor from hashlib import md5, sha1 import io from uuid import uuid4 import imghdr import base64 from closedverse import settings import re from os import remove, rename def HumanTime(date, full=False): now = time.time() time_difference = now - date time_units = {86400: 'day', 3600: 'hour', 60: 'minute'} if time_difference >= 259200 or full: return datetime.fromtimestamp(date).strftime('%m/%d/%Y %I:%M %p') elif time_difference <= 59: return 'Less than a minute ago' else: for unit, unit_name in time_units.items(): if time_difference < unit: continue else: number_of_units = floor(time_difference / unit) if number_of_units > 1: unit_name += 's' return f'{number_of_units} {unit_name} ago' def get_mii(id): # Using AccountWS dmca = { 'X-Nintendo-Client-ID': 'a2efa818a34fa16b8afbc8a74eba3eda', 'X-Nintendo-Client-Secret': 'c91cdb5658bd4954ade78533a339cf9a', } # TODO: Make this, the gravatar request, and reCAPTCHA request escape (or plainly use) URL params nnid = requests.get('https://accountws.nintendo.net/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input=' + id, headers=dmca) nnid_dec = etree.fromstring(nnid.content) del(nnid) pid = nnid_dec[0][1].text if not pid: return False del(nnid_dec) mii = requests.get('https://accountws.nintendo.net/v1/api/miis?pids=' + pid, headers=dmca) try: mii_dec = etree.fromstring(mii.content) # Can't be fucked to put individual exceptions to catch here except: return False del(mii) try: miihash = mii_dec[0][2][0][0].text.split('.net/')[1].split('_')[0] except IndexError: miihash = None screenname = mii_dec[0][3].text nnid = mii_dec[0][6].text del(mii_dec) # Also todo: Return the NNID based on what accountws returns, not the user's input!!! return [miihash, screenname, nnid] def recaptcha_verify(request, key): if not request.POST.get('g-recaptcha-response'): return False re_request = urllib.request.urlopen('https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}'.format(key, request.POST['g-recaptcha-response'])) jsond = json.loads(re_request.read().decode()) if not jsond['success']: return False return True ImageFile.LOAD_TRUNCATED_IMAGES = True def image_upload(img, stream=False, drawing=False): try: # Decode the image decodedimg = img.read() if stream else base64.b64decode(img) # Open the image im = Image.open(io.BytesIO(decodedimg)) # Check for EXIF data and rotate the image if necessary if hasattr(im, '_getexif'): orientation = 0x0112 exif = im._getexif() if exif is not None: orientation = exif.get(orientation) rotations = { 3: Image.ROTATE_180, 6: Image.ROTATE_270, 8: Image.ROTATE_90 } if orientation in rotations: im = im.transpose(rotations[orientation]) # Resize the image im.thumbnail((800, 800), Image.ANTIALIAS) # Check the aspect ratio if this is a drawing if drawing and ((im.size[0] / im.size[1]) < 0.30): return 1 # Generate a hash of the image imhash = sha1(im.tobytes()).hexdigest() # Set the file format and location target = 'webp' floc = imhash + '.' + target # Save the file if it doesn't already exist if not os.path.exists(settings.MEDIA_ROOT + floc): im.save(settings.MEDIA_ROOT + floc, target, quality=80, method=6) # Return the URL of the file return settings.MEDIA_URL + floc # Catch any errors except (OSError, SyntaxError, ValueError): return 1 # Todo: Put this into post/comment delete thingy method def image_rm(image_url): if settings.image_delete_opt: if settings.MEDIA_URL in image_url: sysfile = image_url.split(settings.MEDIA_URL)[1] sysloc = settings.MEDIA_ROOT + sysfile if settings.image_delete_opt > 1: try: remove(sysloc) except: return False else: return True # The RM'd directory to move it to rmloc = sysloc.replace(settings.MEDIA_ROOT, settings.MEDIA_ROOT + 'rm/') try: rename(sysloc, rmloc) except: return False else: return True else: return False def get_gravatar(email): try: page = urllib.request.urlopen('https://gravatar.com/avatar/'+ md5(email.encode('utf-8').lower()).hexdigest() +'?d=404&s=128') except: return False return page.geturl() def filterchars(str=""): # If string is blank, None, any other object, etc, make it whitespace so it's detected by isspace. if not str: str = " " # Forbid chars in this list, currently: Right-left override, largest Unicode character. # Now restricting everything in https://www.reddit.com/r/Unicode/comments/5qa7e7/widestlongest_unicode_characters_list/ forbid = ["\u202e", "\ufdfd", "\u01c4", "\u0601", "\u2031", "\u0bb9", "\u0bf8", "\u0bf5", "\ua9c4", "\u102a", "\ua9c5", "\u2e3b", "\ud808", "\ude19", "\ud809", "\udc2b", "\ud808", "\udf04", "\ud808", "\ude1f", "\ud808", "\udf7c", "\ud808", "\udc4e", "\ud808", "\udc31", "\ud808", "\udf27", "\ud808", "\udd43", "\ud808", "\ude13", "\ud808", "\udf59", "\ud808", "\ude8e", "\ud808", "\udd21", "\ud808", "\udd4c", "\ud808", "\udc4f", "\ud808", "\udc30", "\ud809", "\udc2a", "\ud809", "\udc29", "\ud808", "\ude19", "\ud809", "\udc2b"] for char in forbid: if char in str: str = str.replace(char, " ") if str.isspace(): try: girls = json.load(open(settings.BASE_DIR + '/girls.json')) except: girls = ['None'] return choice(girls) return str # Check IP for proxy. def iphub(addr): if settings.iphub_key and not '192.168' in addr: get = requests.get('http://v2.api.iphub.info/ip/' + addr, headers={'X-Key': settings.iphub_key}) if get.json()['block'] == 1: return True else: return False # NNID blacklist check def nnid_blacked(nnid): blacklist = json.load(open(settings.nnid_forbiddens)) # The NNID server omits dashes and dots from NNIDs, gotta make sure nobody gets through this nnid = nnid.lower().replace('-', '').replace('.', '') if nnid in blacklist: return True return False