Commit 6aa87096 authored by Oliver Falk's avatar Oliver Falk
Browse files

Merge branch 'devel' into 'master'

v1.5 massive (code) update

See merge request !191
parents 12d69576 355af235
Pipeline #2285 passed with stages
in 7 minutes and 13 seconds
......@@ -7,8 +7,12 @@ omit =
import_libravatar.py
requirements.txt
static/admin/*
static/humans.txt
static/img/robots.txt
**/static/humans.txt
**/static/img/robots.txt
ivatar/ivataraccount/read_libravatar_export.py
templates/maintenance.html
encryption_test.py
libravatarproxy.py
[html]
......
[flake8]
ignore = E501, W503, E402
max-line-length = 79
max-complexity = 18
select = B,C,E,F,W,T4,B9
exclude = .git,__pycache__,.virtualenv
fail_fast: true
repos:
- repo: meta
hooks:
- id: check-useless-excludes
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.4.0
hooks:
- id: prettier
files: \.(css|js|md|markdown|json)
- repo: https://github.com/python/black
rev: 21.9b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: check-added-large-files
- id: check-ast
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-json
- id: check-merge-conflict
- id: check-symlinks
- id: check-vcs-permalinks
- id: check-xml
- id: check-yaml
args:
- --unsafe
- id: end-of-file-fixer
- id: fix-encoding-pragma
- id: forbid-new-submodules
- id: no-commit-to-branch
args:
- --branch
- gh-pages
- id: requirements-txt-fixer
- id: sort-simple-yaml
- id: trailing-whitespace
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: local
hooks:
- id: shfmt
name: shfmt
minimum_pre_commit_version: 2.4.0
language: golang
additional_dependencies:
- mvdan.cc/sh/v3/cmd/shfmt@v3.1.1
entry: shfmt
args:
- -w
- -i
- '4'
types:
- shell
- repo: https://github.com/asottile/blacken-docs
rev: v1.11.0
hooks:
- id: blacken-docs
- repo: https://github.com/hcodes/yaspeller.git
rev: v7.0.0
hooks:
- id: yaspeller
types:
- markdown
- repo: https://github.com/kadrach/pre-commit-gitlabci-lint
rev: 22d0495c9894e8b27cc37c2ed5d9a6b46385a44c
hooks:
- id: gitlabci-lint
args: ["https://git.linux-kernel.at"]
''' yes
# -*- coding: utf-8 -*-
"""
Configuration overrides for settings.py
'''
"""
import os
import sys
......@@ -14,50 +15,61 @@ from ivatar.settings import INSTALLED_APPS
from ivatar.settings import TEMPLATES
ADMIN_USERS = []
ALLOWED_HOSTS = ['*']
INSTALLED_APPS.extend([
'django_extensions',
'django_openid_auth',
'bootstrap4',
'anymail',
'ivatar',
'ivatar.ivataraccount',
'ivatar.tools',
])
MIDDLEWARE.extend([
'django.middleware.locale.LocaleMiddleware',
])
ALLOWED_HOSTS = ["*"]
INSTALLED_APPS.extend(
[
"django_extensions",
"django_openid_auth",
"bootstrap4",
"anymail",
"ivatar",
"ivatar.ivataraccount",
"ivatar.tools",
]
)
MIDDLEWARE.extend(
[
"django.middleware.locale.LocaleMiddleware",
]
)
MIDDLEWARE.insert(
0, 'ivatar.middleware.MultipleProxyMiddleware',
0,
"ivatar.middleware.MultipleProxyMiddleware",
)
AUTHENTICATION_BACKENDS = (
# Enable this to allow LDAP authentication.
# See INSTALL for more information.
# 'django_auth_ldap.backend.LDAPBackend',
'django_openid_auth.auth.OpenIDBackend',
'django.contrib.auth.backends.ModelBackend',
"django_openid_auth.auth.OpenIDBackend",
"django.contrib.auth.backends.ModelBackend",
)
TEMPLATES[0]['DIRS'].extend([
os.path.join(BASE_DIR, 'templates'),
])
TEMPLATES[0]['OPTIONS']['context_processors'].append(
'ivatar.context_processors.basepage',
TEMPLATES[0]["DIRS"].extend(
[
os.path.join(BASE_DIR, "templates"),
]
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"ivatar.context_processors.basepage",
)
OPENID_CREATE_USERS = True
OPENID_UPDATE_DETAILS_FROM_SREG = True
SITE_NAME = os.environ.get('SITE_NAME', 'libravatar')
IVATAR_VERSION = '1.4'
SITE_NAME = os.environ.get("SITE_NAME", "libravatar")
IVATAR_VERSION = "1.5"
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/')
SCHEMAROOT = "https://www.libravatar.org/schemas/export/0.2"
LOGIN_REDIRECT_URL = reverse_lazy('profile')
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/")
LOGIN_REDIRECT_URL = reverse_lazy("profile")
MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
MAX_NUM_PHOTOS = 5
......@@ -75,119 +87,120 @@ MIN_LENGTH_EMAIL = 6 # eg. x@x.xx
MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
BOOTSTRAP4 = {
'include_jquery': False,
'javascript_in_head': False,
'css_url': {
'href': '/static/css/bootstrap.min.css',
'integrity':
'sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB',
'crossorigin': 'anonymous',
"include_jquery": False,
"javascript_in_head": False,
"css_url": {
"href": "/static/css/bootstrap.min.css",
"integrity": "sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB",
"crossorigin": "anonymous",
},
'javascript_url': {
'url': '/static/js/bootstrap.min.js',
'integrity': '',
'crossorigin': 'anonymous',
"javascript_url": {
"url": "/static/js/bootstrap.min.js",
"integrity": "",
"crossorigin": "anonymous",
},
'popper_url': {
'url': '/static/js/popper.min.js',
'integrity':
'sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49',
'crossorigin': 'anonymous',
"popper_url": {
"url": "/static/js/popper.min.js",
"integrity": "sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49",
"crossorigin": "anonymous",
},
}
if 'EMAIL_BACKEND' in os.environ:
EMAIL_BACKEND = os.environ['EMAIL_BACKEND'] # pragma: no cover
if "EMAIL_BACKEND" in os.environ:
EMAIL_BACKEND = os.environ["EMAIL_BACKEND"] # pragma: no cover
else:
if 'test' in sys.argv or 'collectstatic' in sys.argv:
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
if "test" in sys.argv or "collectstatic" in sys.argv:
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
else:
try:
ANYMAIL = { # pragma: no cover
'MAILGUN_API_KEY': os.environ['IVATAR_MAILGUN_API_KEY'],
'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
except Exception as exc: # pragma: nocover
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" # pragma: no cover
except Exception: # pragma: nocover # pylint: disable=broad-except
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
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')
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")
try:
from ivatar.settings import DATABASES
except ImportError: # pragma: no cover
DATABASES = [] # pragma: no cover
if 'default' not in DATABASES:
DATABASES['default'] = { # pragma: no cover
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
if "default" not in DATABASES:
DATABASES["default"] = { # pragma: no cover
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
if 'MYSQL_DATABASE' in os.environ:
DATABASES['default'] = { # pragma: no cover
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ['MYSQL_DATABASE'],
'USER': os.environ['MYSQL_USER'],
'PASSWORD': os.environ['MYSQL_PASSWORD'],
'HOST': 'mysql',
if "MYSQL_DATABASE" in os.environ:
DATABASES["default"] = { # pragma: no cover
"ENGINE": "django.db.backends.mysql",
"NAME": os.environ["MYSQL_DATABASE"],
"USER": os.environ["MYSQL_USER"],
"PASSWORD": os.environ["MYSQL_PASSWORD"],
"HOST": "mysql",
}
if 'POSTGRESQL_DATABASE' in os.environ:
DATABASES['default'] = { # pragma: no cover
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['POSTGRESQL_DATABASE'],
'USER': os.environ['POSTGRESQL_USER'],
'PASSWORD': os.environ['POSTGRESQL_PASSWORD'],
'HOST': 'postgresql',
if "POSTGRESQL_DATABASE" in os.environ:
DATABASES["default"] = { # pragma: no cover
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["POSTGRESQL_DATABASE"],
"USER": os.environ["POSTGRESQL_USER"],
"PASSWORD": os.environ["POSTGRESQL_PASSWORD"],
"HOST": "postgresql",
}
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_SERIALIZER = "django.contrib.sessions.serializers.PickleSerializer"
USE_X_FORWARDED_HOST = True
ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = ['avatars.linux-kernel.at', 'localhost',]
ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [
"avatars.linux-kernel.at",
"localhost",
]
DEFAULT_AVATAR_SIZE = 80
LANGUAGES = (
('de', _('Deutsch')),
('en', _('English')),
('ca', _('Català')),
('cs', _('Česky')),
('es', _('Español')),
('eu', _('Basque')),
('fr', _('Français')),
('it', _('Italiano')),
('ja', _('日本語')),
('nl', _('Nederlands')),
('pt', _('Português')),
('ru', _('Русский')),
('sq', _('Shqip')),
('tr', _('Türkçe')),
('uk', _('Українська')),
LANGUAGES = (
("de", _("Deutsch")),
("en", _("English")),
("ca", _("Català")),
("cs", _("Česky")),
("es", _("Español")),
("eu", _("Basque")),
("fr", _("Français")),
("it", _("Italiano")),
("ja", _("日本語")),
("nl", _("Nederlands")),
("pt", _("Português")),
("ru", _("Русский")),
("sq", _("Shqip")),
("tr", _("Türkçe")),
("uk", _("Українська")),
)
MESSAGE_TAGS = {
message_constants.DEBUG: 'debug',
message_constants.INFO: 'info',
message_constants.SUCCESS: 'success',
message_constants.WARNING: 'warning',
message_constants.ERROR: 'danger',
message_constants.DEBUG: "debug",
message_constants.INFO: "info",
message_constants.SUCCESS: "success",
message_constants.WARNING: "warning",
message_constants.ERROR: "danger",
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'127.0.0.1:11211',
],
},
'filesystem': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/ivatar_cache',
'TIMEOUT': 900, # 15 minutes
}
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"LOCATION": [
"127.0.0.1:11211",
],
},
"filesystem": {
"BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
"LOCATION": "/var/tmp/ivatar_cache",
"TIMEOUT": 900, # 15 minutes
},
}
# This is 5 minutes caching for generated/resized images,
......@@ -197,5 +210,5 @@ CACHE_IMAGES_MAX_AGE = 5 * 60
CACHE_RESPONSE = True
# This MUST BE THE LAST!
if os.path.isfile(os.path.join(BASE_DIR, 'config_local.py')):
if os.path.isfile(os.path.join(BASE_DIR, "config_local.py")):
from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover
'''
# -*- coding: utf-8 -*-
"""
Module init
'''
"""
app_label = __name__ # pylint: disable=invalid-name
'''
# -*- coding: utf-8 -*-
"""
Default: useful variables for the base page templates.
'''
"""
from ipware import get_client_ip
from ivatar.settings import IVATAR_VERSION, SITE_NAME, MAX_PHOTO_SIZE
......@@ -9,27 +10,28 @@ from ivatar.settings import MAX_NUM_UNCONFIRMED_EMAILS
def basepage(request):
'''
"""
Our contextprocessor adds additional context variables
in order to be used in the templates
'''
"""
context = {}
if 'openid_identifier' in request.GET:
context['openid_identifier'] = \
request.GET['openid_identifier'] # pragma: no cover
if "openid_identifier" in request.GET:
context["openid_identifier"] = request.GET[
"openid_identifier"
] # pragma: no cover
client_ip = get_client_ip(request)[0]
context['client_ip'] = client_ip
context['ivatar_version'] = IVATAR_VERSION
context['site_name'] = SITE_NAME
context['site_url'] = request.build_absolute_uri('/')[:-1]
context['max_file_size'] = MAX_PHOTO_SIZE
context['BASE_URL'] = BASE_URL
context['SECURE_BASE_URL'] = SECURE_BASE_URL
context['max_emails'] = False
context["client_ip"] = client_ip
context["ivatar_version"] = IVATAR_VERSION
context["site_name"] = SITE_NAME
context["site_url"] = request.build_absolute_uri("/")[:-1]
context["max_file_size"] = MAX_PHOTO_SIZE
context["BASE_URL"] = BASE_URL
context["SECURE_BASE_URL"] = SECURE_BASE_URL
context["max_emails"] = False
if request.user:
if not request.user.is_anonymous:
unconfirmed = request.user.unconfirmedemail_set.count()
if unconfirmed >= MAX_NUM_UNCONFIRMED_EMAILS:
context['max_emails'] = True
context["max_emails"] = True
return context
This diff is collapsed.
'''
# -*- coding: utf-8 -*-
"""
Reading libravatar export
'''
"""
import binascii
import os
from io import BytesIO
import gzip
import xml.etree.ElementTree
import base64
from PIL import Image
import django
import sys
sys.path.append(
os.path.join(
os.path.dirname(__file__),
"..",
"..",
)
)
SCHEMAROOT = 'https://www.libravatar.org/schemas/export/0.2'
os.environ["DJANGO_SETTINGS_MODULE"] = "ivatar.settings"
django.setup()
# pylint: disable=wrong-import-position
from ivatar.settings import SCHEMAROOT
def read_gzdata(gzdata=None):
'''
"""
Read gzipped data file
'''
"""
emails = [] # pylint: disable=invalid-name
openids = [] # pylint: disable=invalid-name
photos = [] # pylint: disable=invalid-name
openids = [] # pylint: disable=invalid-name
photos = [] # pylint: disable=invalid-name
username = None # pylint: disable=invalid-name
password = None # pylint: disable=invalid-name
if not gzdata:
return False
fh = gzip.open(BytesIO(gzdata), 'rb') # pylint: disable=invalid-name
fh = gzip.open(BytesIO(gzdata), "rb") # pylint: disable=invalid-name
content = fh.read()
fh.close()
root = xml.etree.ElementTree.fromstring(content)
if not root.tag == '{%s}user' % SCHEMAROOT:
print('Unknown export format: %s' % root.tag)
if not root.tag == "{%s}user" % SCHEMAROOT:
print("Unknown export format: %s" % root.tag)
exit(-1)
# Username
for item in root.findall('{%s}account' % SCHEMAROOT)[0].items():
if item[0] == 'username':
for item in root.findall("{%s}account" % SCHEMAROOT)[0].items():
if item[0] == "username":
username = item[1]
if item[0] == 'password':
if item[0] == "password":
password = item[1]
# Emails
for email in root.findall('{%s}emails' % SCHEMAROOT)[0]:
if email.tag == '{%s}email' % SCHEMAROOT:
emails.append({'email': email.text, 'photo_id': email.attrib['photo_id']})
for email in root.findall("{%s}emails" % SCHEMAROOT)[0]:
if email.tag == "{%s}email" % SCHEMAROOT:
emails.append({"email": email.text, "photo_id": email.attrib["photo_id"]})
# OpenIDs
for openid in root.findall('{%s}openids' % SCHEMAROOT)[0]:
if openid.tag == '{%s}openid' % SCHEMAROOT:
openids.append({'openid': openid.text, 'photo_id': openid.attrib['photo_id']})
for openid in root.findall("{%s}openids" % SCHEMAROOT)[0]:
if openid.tag == "{%s}openid" % SCHEMAROOT:
openids.append(
{"openid": openid.text, "photo_id": openid.attrib["photo_id"]}
)
# Photos
for photo in root.findall('{%s}photos' % SCHEMAROOT)[0]:
if photo.tag == '{%s}photo' % SCHEMAROOT:
for photo in root.findall("{%s}photos" % SCHEMAROOT)[0]:
if photo.tag == "{%s}photo" % SCHEMAROOT:
try:
data = base64.decodebytes(bytes(photo.text, 'utf-8'))
# Safty measures to make sure we do not try to parse
# a binary encoded string
photo.text = photo.text.strip("'")
photo.text = photo.text.strip("\\n")
photo.text = photo.text.lstrip("b'")
data = base64.decodebytes(bytes(photo.text, "utf-8"))
except binascii.Error as exc:
print('Cannot decode photo; Encoding: %s, Format: %s, Id: %s: %s' % (
photo.attrib['encoding'], photo.attrib['format'], photo.attrib['id'], exc))
print(
"Cannot decode photo; Encoding: %s, Format: %s, Id: %s: %s"
% (
photo.attrib["encoding"],
photo.attrib["format"],
photo.attrib["id"],
exc,
)
)
continue
try:
Image.open(BytesIO(data))
except Exception as exc: # pylint: disable=broad-except
print('Cannot decode photo; Encoding: %s, Format: %s, Id: %s: %s' % (
photo.attrib['encoding'], photo.attrib['format'], photo.attrib['id'], exc))
print(
"Cannot decode photo; Encoding: %s, Format: %s, Id: %s: %s"
% (
photo.attrib["encoding"],
photo.attrib["format"],
photo.attrib["id"],
exc,
)
)
continue
else:
# If it is a working image, we can use it
photo.text.replace('\n', '')
photos.append({
'data': photo.text,
'format': photo.attrib['format'],