mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-18 14:08:04 +00:00
Merge branch 'master' int trust - so it doesn't look stale
This commit is contained in:
@@ -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
|
||||||
|
|||||||
15
config.py
15
config.py
@@ -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')
|
||||||
|
|||||||
@@ -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())
|
|
||||||
@@ -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'
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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> <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> <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>
|
||||||
|
|||||||
@@ -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> 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> 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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
102
ivatar/views.py
102
ivatar/views.py
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user