Merge branch 'master' int trust - so it doesn't look stale

This commit is contained in:
Oliver Falk
2019-03-01 15:50:59 +01:00
13 changed files with 157 additions and 250 deletions

View File

@@ -1,12 +1,9 @@
image: centos:centos7 image: ofalk/centos7-python36
before_script: before_script:
- yum install -y -t https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
- yum -y -t install python36 python34-pip python36-devel unzip mysql-devel gcc git openldap-devel
- pip3 install pip --upgrade
- pip install virtualenv --upgrade
- virtualenv -p python3.6 /tmp/.virtualenv - virtualenv -p python3.6 /tmp/.virtualenv
- source /tmp/.virtualenv/bin/activate - source /tmp/.virtualenv/bin/activate
- pip install Pillow
- pip install -r requirements.txt - pip install -r requirements.txt
- pip install python-coveralls - pip install python-coveralls
- pip install coverage - pip install coverage

View File

@@ -52,7 +52,7 @@ OPENID_CREATE_USERS = True
OPENID_UPDATE_DETAILS_FROM_SREG = True OPENID_UPDATE_DETAILS_FROM_SREG = True
SITE_NAME = os.environ.get('SITE_NAME', 'libravatar') SITE_NAME = os.environ.get('SITE_NAME', 'libravatar')
IVATAR_VERSION = '1.0' IVATAR_VERSION = '1.1'
SECURE_BASE_URL = os.environ.get('SECURE_BASE_URL', 'https://avatars.linux-kernel.at/avatar/') SECURE_BASE_URL = os.environ.get('SECURE_BASE_URL', 'https://avatars.linux-kernel.at/avatar/')
BASE_URL = os.environ.get('BASE_URL', 'http://avatars.linux-kernel.at/avatar/') BASE_URL = os.environ.get('BASE_URL', 'http://avatars.linux-kernel.at/avatar/')
@@ -102,11 +102,14 @@ else:
if 'test' in sys.argv or 'collectstatic' in sys.argv: if 'test' in sys.argv or 'collectstatic' in sys.argv:
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
else: else:
ANYMAIL = { # pragma: no cover try:
'MAILGUN_API_KEY': os.environ['IVATAR_MAILGUN_API_KEY'], ANYMAIL = { # pragma: no cover
'MAILGUN_SENDER_DOMAIN': os.environ['IVATAR_MAILGUN_SENDER_DOMAIN'], 'MAILGUN_API_KEY': os.environ['IVATAR_MAILGUN_API_KEY'],
} 'MAILGUN_SENDER_DOMAIN': os.environ['IVATAR_MAILGUN_SENDER_DOMAIN'],
EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' # pragma: no cover }
EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' # pragma: no cover
except Exception as exc:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
SERVER_EMAIL = os.environ.get('SERVER_EMAIL', 'ivatar@mg.linux-kernel.at') SERVER_EMAIL = os.environ.get('SERVER_EMAIL', 'ivatar@mg.linux-kernel.at')
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'ivatar@mg.linux-kernel.at') DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'ivatar@mg.linux-kernel.at')

View File

@@ -1,139 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Oliver Falk <oliver@linux-kernel.at>
#
# This file is part of Libravatar
#
# Libravatar is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Libravatar is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Libravatar. If not, see <http://www.gnu.org/licenses/>.
import base64
import gzip
import json
import os
import sys
from xml.sax import saxutils
import hashlib
# pylint: disable=relative-import
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "libravatar.settings")
import libravatar.settings as settings
from libravatar.utils import create_logger, is_hex
import django
django.setup()
from django.contrib.auth.models import User
os.umask(022)
LOGGER = create_logger('exportaccount')
SCHEMA_ROOT = 'https://www.libravatar.org/schemas/export/0.2'
SCHEMA_XSD = '%s/export.xsd' % SCHEMA_ROOT
def xml_header():
return '''<?xml version="1.0" encoding="UTF-8"?>
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="%s %s"
xmlns="%s">\n''' % (SCHEMA_ROOT, SCHEMA_XSD, SCHEMA_ROOT)
def xml_footer():
return '</user>\n'
def xml_account(username, password):
escaped_username = saxutils.quoteattr(username)
escaped_site_url = saxutils.quoteattr(settings.SITE_URL)
escaped_password = saxutils.quoteattr(password)
return ' <account username=%s password=%s site=%s/>\n' % (escaped_username, escaped_password, escaped_site_url)
def xml_email(emails):
returnstring = " <emails>\n"
for email in emails:
returnstring += ' <email photo_id="' + str(email.photo_id) + '">' + email.email.encode('utf-8') + '</email>' + "\n"
returnstring += " </emails>\n"
return returnstring
def xml_openid(openids):
returnstring = " <openids>\n"
for openid in openids:
returnstring += ' <openid photo_id="' + str(openid.photo_id) + '">' + openid.openid.encode('utf-8') + '</openid>' + "\n"
returnstring += " </openids>\n"
return returnstring
def xml_photos(photos):
s = ' <photos>\n'
for photo in photos:
(photo_filename, photo_format, id) = photo
encoded_photo = encode_photo(photo_filename, photo_format)
if encoded_photo:
s += ''' <photo id="%s" encoding="base64" format=%s>
%s
</photo>\n''' % (id, saxutils.quoteattr(photo_format), encoded_photo)
s += ' </photos>\n'
return s
def encode_photo(photo_filename, photo_format):
filename = settings.USER_FILES_ROOT + photo_filename + '.' + photo_format
if not os.path.isfile(filename):
LOGGER.warning('Photo not found: %s', filename)
return None
photo_content = None
with open(filename) as photo:
photo_content = photo.read()
if not photo_content:
LOGGER.warning('Could not read photo: %s', filename)
return None
return base64.b64encode(photo_content)
def main(argv=None):
if argv is None:
argv = sys.argv
if(len(sys.argv) > 1):
userobjs = User.objects.filter(username=sys.argv[1])
else:
userobjs = User.objects.all()
for user in userobjs:
hash_object = hashlib.new('sha256')
hash_object.update(user.username + user.password)
file_hash = hash_object.hexdigest()
photos = []
for photo in user.photos.all():
photo_details = (photo.filename, photo.format, photo.id)
photos.append(photo_details)
username = user.username
dest_filename = settings.EXPORT_FILES_ROOT + file_hash + '.xml.gz'
destination = gzip.open(dest_filename, 'w')
destination.write(xml_header())
destination.write(xml_account(username, user.password))
destination.write(xml_email(user.confirmed_emails.all()))
destination.write(xml_openid(user.confirmed_openids.all()))
destination.write(xml_photos(photos))
destination.write(xml_footer())
destination.close()
print(dest_filename)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -37,10 +37,10 @@ from .gravatar import get_photo as get_gravatar_photo
def file_format(image_type): def file_format(image_type):
''' '''
Helper method returning a 3 character long image type Helper method returning a short image type
''' '''
if image_type == 'JPEG': if image_type == 'JPEG':
return 'jpg' return 'jpeg'
elif image_type == 'PNG': elif image_type == 'PNG':
return 'png' return 'png'
elif image_type == 'GIF': elif image_type == 'GIF':
@@ -52,7 +52,7 @@ def pil_format(image_type):
''' '''
Helper method returning the 'encoder name' for PIL Helper method returning the 'encoder name' for PIL
''' '''
if image_type == 'jpg': if image_type == 'jpg' or image_type == 'jpeg':
return 'JPEG' return 'JPEG'
elif image_type == 'png': elif image_type == 'png':
return 'PNG' return 'PNG'

View File

@@ -358,7 +358,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
# Probably not the best way to access the content type # Probably not the best way to access the content type
self.assertEqual( self.assertEqual(
response['Content-Type'], response['Content-Type'],
'image/jpg', 'image/jpeg',
'Content type wrong!?') 'Content type wrong!?')
self.assertEqual( self.assertEqual(
@@ -638,10 +638,10 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
self.assertEqual( self.assertEqual(
str(list(response.context[0]['messages'])[0]), str(list(response.context[0]['messages'])[0]),
'Successfully uploaded', 'Successfully uploaded',
'JPG upload failed?!') 'JPEG upload failed?!')
self.assertEqual( self.assertEqual(
self.user.photo_set.first().format, 'jpg', self.user.photo_set.first().format, 'jpeg',
'Format must be jpg, since we uploaded a jpg!') 'Format must be jpeg, since we uploaded a jpeg!')
self.test_confirm_email() self.test_confirm_email()
self.user.confirmedemail_set.first().photo = self.user.photo_set.first() self.user.confirmedemail_set.first().photo = self.user.photo_set.first()
urlobj = urlsplit( urlobj = urlsplit(

View File

@@ -914,6 +914,9 @@ class PasswordResetView(PasswordResetViewOriginal):
try: try:
confirmed_email = ConfirmedEmail.objects.get(email=request.POST['email']) confirmed_email = ConfirmedEmail.objects.get(email=request.POST['email'])
confirmed_email.user.email = confirmed_email.email confirmed_email.user.email = confirmed_email.email
if not confirmed_email.user.password:
random_pass = User.objects.make_random_password()
confirmed_email.user.set_pasword(random_pass)
confirmed_email.user.save() confirmed_email.user.save()
except Exception as exc: except Exception as exc:
pass pass

View File

@@ -56,8 +56,10 @@ class CheckForm(forms.Form):
required=True, required=True,
) )
default_url = forms.URLField( default_url = forms.CharField(
label=_('Default URL'), label=_('Default URL'),
min_length=1,
max_length=MAX_LENGTH_URL,
required=False, required=False,
) )

View File

@@ -8,6 +8,12 @@
<h1>{% trans 'Check e-mail or openid' %}</h1> <h1>{% trans 'Check e-mail or openid' %}</h1>
{% if form.errors %}
<p class="error">{% trans "Please correct errors below:" %}<br>
{{ form.errors|join:', ' }}
</p>
{% endif %}
<div style="max-width:640px"> <div style="max-width:640px">
<form method="post" name="check"> <form method="post" name="check">
{% csrf_token %} {% csrf_token %}
@@ -17,8 +23,8 @@
<input type="text" name="openid" maxlength="255" minlength="11" class="form-control" placeholder="{% trans 'OpenID' %}" {% if openidurl %} value="{{ form.openid.value }}" {% endif %} id="id_openid"></div> <input type="text" name="openid" maxlength="255" minlength="11" class="form-control" placeholder="{% trans 'OpenID' %}" {% if openidurl %} value="{{ form.openid.value }}" {% endif %} id="id_openid"></div>
<div class="form-group"><label for="id_size">{% trans 'Size' %}</label> <div class="form-group"><label for="id_size">{% trans 'Size' %}</label>
<input type="number" name="size" min="5" max="512" class="form-control" placeholder="{% trans 'Size' %}" {% if mailurl or openidurl %} value="{{ form.size.value }}" {% else %} value="100" {% endif %} required id="id_size"></div> <input type="number" name="size" min="5" max="512" class="form-control" placeholder="{% trans 'Size' %}" {% if mailurl or openidurl %} value="{{ form.size.value }}" {% else %} value="100" {% endif %} required id="id_size"></div>
<div class="form-group"><label for="id_default_url">{% trans 'Default URL' %}</label> <div class="form-group"><label for="id_default_url">{% trans 'Default URL or special keyword' %}</label>
<input type="url" name="default_url" class="form-control" placeholder="{% trans 'Default URL' %}" {% if mailurl or openidurl %} value="{{ form.default_url.value }}" {% endif %} id="id_default_url"></div> <input type="text" name="default_url" class="form-control" placeholder="{% trans 'Default' %}" {% if mailurl or openidurl %} value="{{ form.default_url.value }}" {% endif %} id="id_default_url"></div>
<div class="form-group"> <div class="form-group">
<button type="submit" class="btn btn-default">{% trans 'Check' %}</button> <button type="submit" class="btn btn-default">{% trans 'Check' %}</button>
</div> </div>
@@ -56,8 +62,8 @@
<h3 class="panel-title">SHA256 <i class="fa fa-lock" title="Secure connection (https)"></i>&nbsp;<i class="fa fa-at" title="mail: {{ form.mail.value }}"></i></h3> <h3 class="panel-title">SHA256 <i class="fa fa-lock" title="Secure connection (https)"></i>&nbsp;<i class="fa fa-at" title="mail: {{ form.mail.value }}"></i></h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<a href="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}"> <a href="{{ mailurl_secure_256 }}">
<center><img src="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}" style="max-width: {{ size }}px; max-height: {{ size }}px;"></center> <center><img src="{{ mailurl_secure_256 }}" style="max-width: {{ size }}px; max-height: {{ size }}px;"></center>
</a> </a>
</div> </div>
</div> </div>

View File

@@ -37,44 +37,51 @@
<!-- TODO TODO TODO: I need better styling --> <!-- TODO TODO TODO: I need better styling -->
{% if result %} {% if result %}
<hr/> <hr/>
<table> <h2>The following servers will be used for your domain</h2>
<tr> <div class="panel panel-tortin" style="width:intrinsic;margin-left:30px;float:left">
<td valign="top" style="padding: 0px 10px 0px 10px;">{% trans 'HTTP avatar server:' %}</td> <div class="panel-heading">
<td> <h3 class="panel-title"><i class="fa fa-unlock-alt"></i>&nbsp;HTTP Server</h3>
{% if result.avatar_server_http %} </div>
<tt>{{result.avatar_server_http}}</tt> <div class="panel-body">
{% if result.avatar_server_http_ipv4 %} {% if result.avatar_server_http %}
<br>{{ result.avatar_server_http_ipv4 }} <a href="{{result.avatar_server_http}}">
{% else %} <h4>{{result.avatar_server_http}}</h4>
<br><strong>{% trans 'Warning: no A record for this hostname' %}</strong> </a>
{% endif %} {% if result.avatar_server_http_ipv4 %}
{% if result.avatar_server_http_ipv6 %} <br><center>{{ result.avatar_server_http_ipv4 }}</center>
<br>{{ result.avatar_server_http_ipv6 }} {% endif %}
{% endif %} {% if result.avatar_server_http_ipv6 %}
{% else %} <br><center>{{ result.avatar_server_http_ipv6 }}</center>
<i>{% trans 'use <tt>http://cdn.libravatar.org</tt>' %}</i> {% endif %}
{% endif %} {% else %}
</td> <a href="http://cdn.libravatar.org">
</tr> <h4>http://cdn.libravatar.org</h4>
<tr> </a>
<td valign="top" style="padding: 0px 10px 0px 10px;">{% trans 'HTTPS avatar server:' %}</td> {% endif %}
<td> </div>
{% if result.avatar_server_https %} </div>
<tt>{{result.avatar_server_https}}</tt> <div class="panel panel-tortin" style="width:intrinsic;margin-left:30px;float:left">
{% if result.avatar_server_https_ipv4 %} <div class="panel-heading">
<br>{{ result.avatar_server_https_ipv4 }} <h3 class="panel-title"><i class="fa fa-lock"></i>&nbsp;HTTPS Server</h3>
{% else %} </div>
<br><strong>{% trans 'Warning: no A record for this hostname' %}</strong> <div class="panel-body">
{% endif %} {% if result.avatar_server_https %}
{% if result.avatar_server_https_ipv6 %} <a href="{{result.avatar_server_https}}">
<br>{{ result.avatar_server_https_ipv6 }} <h4>{{result.avatar_server_https}}</h4>
{% endif %} </a>
{% else %} {% if result.avatar_server_https_ipv4 %}
<i>{% trans 'use <tt>https://seccdn.libravatar.org</tt>' %}</i> <br><center>{{ result.avatar_server_https_ipv4 }}</center>
{% endif %} {% endif %}
</td> {% if result.avatar_server_https_ipv6 %}
</tr> <br><center>{{ result.avatar_server_https_ipv6 }}</center>
</table> {% endif %}
{% else %}
<a href="https://seccdn.libravatar.org">
<h4>https://seccdn.libravatar.org</h4>
</a>
{% endif %}
</div>
</div>
{% endif %} {% endif %}
</div> </div>
<div style="height:40px"></div> <div style="height:40px"></div>

View File

@@ -66,15 +66,17 @@ class CheckView(FormView):
else: else:
default_url = None default_url = None
if 'size' in form.cleaned_data:
size = form.cleaned_data['size']
if form.cleaned_data['mail']: if form.cleaned_data['mail']:
mailurl = libravatar_url( mailurl = libravatar_url(
email=form.cleaned_data['mail'], email=form.cleaned_data['mail'],
size=form.cleaned_data['size'], size=size,
default=default_url) default=default_url)
mailurl = mailurl.replace(LIBRAVATAR_BASE_URL, BASE_URL) mailurl = mailurl.replace(LIBRAVATAR_BASE_URL, BASE_URL)
mailurl_secure = libravatar_url( mailurl_secure = libravatar_url(
email=form.cleaned_data['mail'], email=form.cleaned_data['mail'],
size=form.cleaned_data['size'], size=size,
https=True, https=True,
default=default_url) default=default_url)
mailurl_secure = mailurl_secure.replace( mailurl_secure = mailurl_secure.replace(
@@ -86,18 +88,20 @@ class CheckView(FormView):
hash_obj = hashlib.new('sha256') hash_obj = hashlib.new('sha256')
hash_obj.update(form.cleaned_data['mail'].encode('utf-8')) hash_obj.update(form.cleaned_data['mail'].encode('utf-8'))
mail_hash256 = hash_obj.hexdigest() mail_hash256 = hash_obj.hexdigest()
size = form.cleaned_data['size'] mailurl_secure_256 = mailurl_secure.replace(
mail_hash,
mail_hash256)
if form.cleaned_data['openid']: if form.cleaned_data['openid']:
if not form.cleaned_data['openid'].startswith('http://') and not form.cleaned_data['openid'].startswith('https://'): if not form.cleaned_data['openid'].startswith('http://') and not form.cleaned_data['openid'].startswith('https://'):
form.cleaned_data['openid'] = 'http://%s' % form.cleaned_data['openid'] form.cleaned_data['openid'] = 'http://%s' % form.cleaned_data['openid']
openidurl = libravatar_url( openidurl = libravatar_url(
openid=form.cleaned_data['openid'], openid=form.cleaned_data['openid'],
size=form.cleaned_data['size'], size=size,
default=default_url) default=default_url)
openidurl = openidurl.replace(LIBRAVATAR_BASE_URL, BASE_URL) openidurl = openidurl.replace(LIBRAVATAR_BASE_URL, BASE_URL)
openidurl_secure = libravatar_url( openidurl_secure = libravatar_url(
openid=form.cleaned_data['openid'], openid=form.cleaned_data['openid'],
size=form.cleaned_data['size'], size=size,
https=True, https=True,
default=default_url) default=default_url)
openidurl_secure = openidurl_secure.replace( openidurl_secure = openidurl_secure.replace(
@@ -106,13 +110,13 @@ class CheckView(FormView):
openid_hash = parse_user_identity( openid_hash = parse_user_identity(
openid=form.cleaned_data['openid'], openid=form.cleaned_data['openid'],
email=None)[0] email=None)[0]
size = form.cleaned_data['size']
return render(self.request, self.template_name, { return render(self.request, self.template_name, {
'form': form, 'form': form,
'mailurl': mailurl, 'mailurl': mailurl,
'openidurl': openidurl, 'openidurl': openidurl,
'mailurl_secure': mailurl_secure, 'mailurl_secure': mailurl_secure,
'mailurl_secure_256': mailurl_secure_256,
'openidurl_secure': openidurl_secure, 'openidurl_secure': openidurl_secure,
'mail_hash': mail_hash, 'mail_hash': mail_hash,
'mail_hash256': mail_hash256, 'mail_hash256': mail_hash256,

View File

@@ -16,7 +16,9 @@ from django.urls import reverse_lazy
from PIL import Image from PIL import Image
from monsterid.id import build_monster as BuildMonster from monsterid.id import build_monster as BuildMonster
from pydenticon import Generator as IdenticonGenerator import Identicon
from pydenticon5 import Pydenticon5
import pagan
from robohash import Robohash from robohash import Robohash
from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE
@@ -120,6 +122,14 @@ class AvatarImageView(TemplateView):
# Return the default URL, as specified, or 404 Not Found, if default=404 # Return the default URL, as specified, or 404 Not Found, if default=404
if default: if default:
# Proxy to gravatar to generate wavatar - lazy me
if str(default) == 'wavatar':
url = reverse_lazy('gravatarproxy', args=[kwargs['digest']]) \
+ '?s=%i' % size + '&default=%s&f=y' % default
return HttpResponseRedirect(url)
if str(default) == str(404): if str(default) == str(404):
return HttpResponseNotFound(_('<h1>Image not found</h1>')) return HttpResponseNotFound(_('<h1>Image not found</h1>'))
@@ -145,32 +155,35 @@ class AvatarImageView(TemplateView):
data, data,
content_type='image/png') content_type='image/png')
if str(default) == 'identicon' or str(default) == 'retro': if str(default) == 'retro':
# Taken from example code identicon = Identicon.render(kwargs['digest'])
foreground = [ data = BytesIO()
'rgb(45,79,255)', img = Image.open(BytesIO(identicon))
'rgb(254,180,44)', img = img.resize((size, size), Image.ANTIALIAS)
'rgb(226,121,234)', img.save(data, 'PNG', quality=JPEG_QUALITY)
'rgb(30,179,253)', data.seek(0)
'rgb(232,77,65)', return HttpResponse(
'rgb(49,203,115)', data,
'rgb(141,69,170)'] content_type='image/png')
background = 'rgb(224,224,224)'
padwidth = int(size/10) if str(default) == 'pagan':
if padwidth < 10: paganobj = pagan.Avatar(kwargs['digest'])
padwidth = 10 data = BytesIO()
if size < 60: img = paganobj.img.resize((size, size), Image.ANTIALIAS)
padwidth = 0 img.save(data, 'PNG', quality=JPEG_QUALITY)
padding = (padwidth, padwidth, padwidth, padwidth) data.seek(0)
# Since padding is _added_ around the generated image, we return HttpResponse(
# need to reduce the image size by padding*2 (left/right, top/bottom) data,
size = size - 2*padwidth content_type='image/png')
generator = IdenticonGenerator(
10, 10, digest=hashlib.sha1, if str(default) == 'identicon':
foreground=foreground, background=background) p = Pydenticon5()
data = generator.generate( # In order to make use of the whole 32 bytes digest, we need to redigest them.
kwargs['digest'], size, size, newdigest = hashlib.md5(bytes(kwargs['digest'], 'utf-8')).hexdigest()
output_format='png', padding=padding, inverted=False) img = p.draw(newdigest, size, 0)
data = BytesIO()
img.save(data, 'PNG', quality=JPEG_QUALITY)
data.seek(0)
return HttpResponse( return HttpResponse(
data, data,
content_type='image/png') content_type='image/png')
@@ -194,8 +207,12 @@ class AvatarImageView(TemplateView):
imgformat = obj.photo.format imgformat = obj.photo.format
photodata = Image.open(BytesIO(obj.photo.data)) photodata = Image.open(BytesIO(obj.photo.data))
# If the image is smaller than what was requested, we need
photodata.thumbnail((size, size), Image.ANTIALIAS) # to use the function resize
if photodata.size[0] < size or photodata.size[1] < size:
photodata = photodata.resize((size, size), Image.ANTIALIAS)
else:
photodata.thumbnail((size, size), Image.ANTIALIAS)
data = BytesIO() data = BytesIO()
photodata.save(data, pil_format(imgformat), quality=JPEG_QUALITY) photodata.save(data, pil_format(imgformat), quality=JPEG_QUALITY)
data.seek(0) data.seek(0)
@@ -235,21 +252,22 @@ class GravatarProxyView(View):
except: except:
pass pass
# This part is special/hackish if str(default) != 'wavatar':
# Check if the image returned by Gravatar is their default image, if so, # This part is special/hackish
# redirect to our default instead. # Check if the image returned by Gravatar is their default image, if so,
gravatar_test_url = 'https://secure.gravatar.com/avatar/' + kwargs['digest'] \ # redirect to our default instead.
+ '?s=%i' % 50 gravatar_test_url = 'https://secure.gravatar.com/avatar/' + kwargs['digest'] \
try: + '?s=%i' % 50
testdata = urlopen(gravatar_test_url, timeout=URL_TIMEOUT) try:
data = BytesIO(testdata.read()) testdata = urlopen(gravatar_test_url, timeout=URL_TIMEOUT)
if hashlib.md5(data.read()).hexdigest() == '71bc262d627971d13fe6f3180b93062a': data = BytesIO(testdata.read())
return redir_default(default) if hashlib.md5(data.read()).hexdigest() == '71bc262d627971d13fe6f3180b93062a':
except Exception as exc: return redir_default(default)
print('Gravatar test url fetch failed: %s' % exc) except Exception as exc:
print('Gravatar test url fetch failed: %s' % exc)
gravatar_url = 'https://secure.gravatar.com/avatar/' + kwargs['digest'] \ gravatar_url = 'https://secure.gravatar.com/avatar/' + kwargs['digest'] \
+ '?s=%i' % size + '?s=%i' % size + '&d=%s' % default
try: try:
gravatarimagedata = urlopen(gravatar_url, timeout=URL_TIMEOUT) gravatarimagedata = urlopen(gravatar_url, timeout=URL_TIMEOUT)

View File

@@ -33,6 +33,8 @@ mysqlclient
psycopg2 psycopg2
notsetuptools notsetuptools
git+https://github.com/ofalk/monsterid.git git+https://github.com/ofalk/monsterid.git
git+https://github.com/azaghal/pydenticon.git
git+https://github.com/ofalk/Robohash.git@devel git+https://github.com/ofalk/Robohash.git@devel
python-memcached python-memcached
git+https://github.com/ercpe/pydenticon5.git
git+https://github.com/flavono123/identicon.git
pagan

View File

@@ -45,8 +45,12 @@
</a> </a>
<ul class="dropdown-menu" aria-labelledby="tools_dropdown"> <ul class="dropdown-menu" aria-labelledby="tools_dropdown">
<li><a id="tools-check" href="{% url 'tools_check' %}"> <li><a id="tools-check" href="{% url 'tools_check' %}">
<i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check' %} <i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check ID' %}
</a></li> </a></li>
<li><a id="tools-check-domain" href="{% url 'tools_check_domain' %}">
<i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check Domain' %}
</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>