16 Commits

Author SHA1 Message Date
Oliver Falk
b6ccc9bbc1 Update gpg key 2022-05-06 17:22:43 +02:00
Oliver Falk
b160c52252 Merge branch 'devel' into trust 2022-02-18 14:16:19 +01:00
Oliver Falk
c0176f46b6 Merge branch 'devel' into trust 2021-09-10 13:02:53 +02:00
Oliver Falk
22ee2258c3 Merge branch 'master' into trust 2021-09-10 12:47:04 +02:00
Oliver Falk
800a0c4735 Merge branch 'devel' into trust 2020-02-25 16:41:24 +01:00
Oliver Falk
040685f26b Merge branch 'master' into trust 2020-02-25 13:48:04 +01:00
Oliver Falk
e64e1fe7fb Merge branch 'devel' into trust 2020-02-25 13:45:22 +01:00
Oliver Falk
7be372461d Merge branch 'devel' into trust 2019-08-02 15:32:32 +02:00
Oliver Falk
5e98e09cc9 Merge branch 'master' of git.linux-kernel.at:oliver/ivatar into trust 2019-05-08 10:33:44 +02:00
Oliver Falk
f7c18b8c8a Merge branch 'devel' into trust 2019-03-01 15:54:40 +01:00
Oliver Falk
59696485b4 Merge branch 'master' into trust 2019-03-01 15:53:35 +01:00
Oliver Falk
fd919e4a3e Merge branch 'master' int trust - so it doesn't look stale 2019-03-01 15:51:24 +01:00
Oliver Falk
c04984d68a Merge branch 'devel' into trust 2019-02-21 10:01:07 +01:00
Oliver Falk
2ad826a04e Update pubkeys 2018-11-15 10:51:30 +01:00
Oliver Falk
d4a903f743 Add gpg pubkey 2018-11-15 10:51:02 +01:00
Oliver Falk
54f92016bc Add pubkeys - temporarily 2018-11-15 08:15:19 +01:00
12 changed files with 29 additions and 323 deletions

View File

@@ -14,7 +14,6 @@ before_script:
test_and_coverage:
stage: test
coverage: '/^TOTAL.*\s+(\d+\%)$/'
script:
- echo 'from ivatar.settings import TEMPLATES' > config_local.py
- echo 'TEMPLATES[0]["OPTIONS"]["debug"] = True' >> config_local.py

View File

@@ -4,16 +4,16 @@ repos:
hooks:
- id: check-useless-excludes
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.6.2
rev: v2.4.0
hooks:
- id: prettier
files: \.(css|js|md|markdown|json)
- repo: https://github.com/python/black
rev: 22.3.0
rev: 21.9b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
rev: v4.0.1
hooks:
- id: check-added-large-files
- id: check-ast
@@ -57,11 +57,11 @@ repos:
types:
- shell
- repo: https://github.com/asottile/blacken-docs
rev: v1.12.1
rev: v1.11.0
hooks:
- id: blacken-docs
- repo: https://github.com/hcodes/yaspeller.git
rev: v8.0.1
rev: v7.0.0
hooks:
- id: yaspeller

View File

@@ -1,6 +1,6 @@
# Installation
## Prerequisites
## Prequisits
Python 3.x + virtualenv
@@ -10,13 +10,6 @@ Python 3.x + virtualenv
yum install python34-virtualenv.noarch
```
### Debian 11
```
sudo apt-get update
sudo apt-get install git python3-virtualenv libmariadb-dev libldap2-dev libsasl2-dev
```
## Checkout
~~~~bash
@@ -29,8 +22,8 @@ cd ivatar
~~~~bash
virtualenv -p python3 .virtualenv
source .virtualenv/bin/activate
pip install pillow
pip install -r requirements.txt
pip install pillow
~~~~
## (SQL) Migrations

View File

@@ -211,72 +211,19 @@ CACHE_RESPONSE = True
# Trusted URLs for default redirection
TRUSTED_DEFAULT_URLS = [
{
"schemes": [
"https"
],
"host_equals": "ui-avatars.com",
"path_prefix": "/api/"
},
{
"schemes": [
"http",
"https"
],
"host_equals": "gravatar.com",
"path_prefix": "/avatar/"
},
{
"schemes": [
"http",
"https"
],
"host_suffix": ".gravatar.com",
"path_prefix": "/avatar/"
},
{
"schemes": [
"http",
"https"
],
"host_equals": "www.gravatar.org",
"path_prefix": "/avatar/"
},
{
"schemes": [
"https"
],
"host_equals": "avatars.dicebear.com",
"path_prefix": "/api/"
},
{
"schemes": [
"https"
],
"host_equals": "badges.fedoraproject.org",
"path_prefix": "/static/img/"
},
{
"schemes": [
"http",
],
"host_equals": "www.planet-libre.org",
"path_prefix": "/themes/planetlibre/images/"
},
{
"schemes": [
"https"
],
"host_equals": "www.azuracast.com",
"path_prefix": "/img/"
},
{
"schemes": [
"https"
],
"host_equals": "reps.mozilla.org",
"path_prefix": "/static/base/img/remo/"
}
"https://ui-avatars.com/api/",
"http://gravatar.com/avatar/",
"https://gravatar.com/avatar/",
"http://www.gravatar.org/avatar/",
"https://www.gravatar.org/avatar/",
"https://secure.gravatar.com/avatar/",
"http://0.gravatar.com/avatar/",
"https://0.gravatar.com/avatar/",
"https://avatars.dicebear.com/api/",
"https://badges.fedoraproject.org/static/img/",
"http://www.planet-libre.org/themes/planetlibre/images/",
"https://www.azuracast.com/img/",
"https://reps.mozilla.org/static/base/img/remo/",
]
# This MUST BE THE LAST!

1
gpg-pubkey Normal file
View File

@@ -0,0 +1 @@
1B4A3476CB99010178CEAB5C00C0EF248E1F4575

View File

@@ -1,78 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Import a CSV - Format as follows:
<mailaddr>,<path_to_image>
Example:
myuser@mydomain.tld,myphoto.jpeg
This will create or update an existing user and assign the image
to the given address.
"""
import os
from os.path import isfile
import sys
from io import BytesIO
import csv
import django
os.environ.setdefault(
"DJANGO_SETTINGS_MODULE", "ivatar.settings"
) # pylint: disable=wrong-import-position
django.setup() # pylint: disable=wrong-import-position
from django.contrib.auth.models import User
from PIL import Image
from ivatar.settings import JPEG_QUALITY
from ivatar.ivataraccount.models import ConfirmedEmail
from ivatar.ivataraccount.models import Photo
from ivatar.ivataraccount.models import file_format
if len(sys.argv) < 2:
print("First argument to '%s' must be the path to the CSV" % sys.argv[0])
exit(-255)
if not isfile(sys.argv[1]):
print("First argument to '%s' must be a path to the CSV" % sys.argv[0])
exit(-255)
PATH = sys.argv[1]
with open(PATH, newline="") as csvfile:
contactreader = csv.reader(csvfile, delimiter=",")
for row in contactreader:
mailaddr = row[0]
image = row[1]
if not isfile(image):
print("File '%s' doesn't exist - cannot add" % image)
continue
print("Adding: %s" % mailaddr)
(user, created) = User.objects.get_or_create(username=mailaddr)
if not user.confirmedemail_set.count() < 1:
ConfirmedEmail.objects.get_or_create(
email=mailaddr,
user=user,
)
user.save()
with open(image, "rb") as avatar:
pilobj = Image.open(avatar)
out = BytesIO()
pilobj.save(out, pilobj.format, quality=JPEG_QUALITY)
out.seek(0)
photo = None
if user.photo_set.count() < 1:
photo = Photo()
photo.user = user
else:
photo = user.photo_set.first()
photo.ip_address = "0.0.0.0"
photo.format = file_format(pilobj.format)
photo.data = out.read()
photo.save()
print("xxx: %s" % user.confirmedemail_set.first())
confirmed_email = user.confirmedemail_set.first()
confirmed_email.photo_id = photo.id
confirmed_email.save()

View File

@@ -113,7 +113,7 @@
</li>
<li class="email-delete">
<button type="submit" class="nobutton" onclick="return confirm('{% trans 'Are you sure that you want to delete this email address?' %}')">
Delete Email Address
Delete Email Adress
</button>
</li>
</ul>
@@ -135,7 +135,7 @@
</li>
<li class="email-delete">
<button type="submit" class="nobutton" onclick="return confirm('{% trans 'Are you sure that you want to delete this email address?' %}')">
Delete Email Address
Delete Email Adress
</button>
</li>
</ul>

View File

@@ -1830,63 +1830,4 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
Test if uploading export works
"""
# Ensure we have data in place
self.test_export()
self.login()
self.client.get(reverse("export"))
response = self.client.post(
reverse("export"),
{},
follow=False,
)
self.assertIsInstance(response.content, bytes)
fh_gzip = gzip.open(BytesIO(response.content), "rb")
fh = BytesIO(response.content)
response = self.client.post(
reverse("upload_export"),
data={"not_porn": "on", "can_distribute": "on", "export_file": fh_gzip},
follow=True,
)
fh_gzip.close()
self.assertEqual(response.status_code, 200, "Upload worked")
self.assertContains(
response,
"Unable to parse file: Not a gzipped file",
1,
200,
"Upload didn't work?",
)
# Second test - correctly gzipped content
response = self.client.post(
reverse("upload_export"),
data={"not_porn": "on", "can_distribute": "on", "export_file": fh},
follow=True,
)
fh.close()
self.assertEqual(response.status_code, 200, "Upload worked")
self.assertContains(
response,
"Choose items to be imported",
1,
200,
"Upload didn't work?",
)
self.assertContains(
response,
"asdf@asdf.local",
2,
200,
"Upload didn't work?",
)
def test_prefs_page(self):
"""
Test if preferences page works
"""
self.client.get(reverse("user_preference"))
self.client.get(reverse("upload_export"))

View File

@@ -5,7 +5,7 @@ Test our utils from ivatar.utils
from django.test import TestCase
from ivatar.utils import is_trusted_url, openid_variations
from ivatar.utils import openid_variations
class Tester(TestCase):
@@ -45,60 +45,3 @@ class Tester(TestCase):
self.assertEqual(openid_variations(openid3)[1], openid1)
self.assertEqual(openid_variations(openid3)[2], openid2)
self.assertEqual(openid_variations(openid3)[3], openid3)
def test_is_trusted_url(self):
test1 = is_trusted_url("https://gravatar.com/avatar/63a75a80e6b1f4adfdb04c1ca02e596c", [
{
"schemes": [
"http",
"https"
],
"host_equals": "gravatar.com",
"path_prefix": "/avatar/"
}
])
self.assertTrue(test1)
test2 = is_trusted_url("https://gravatar.com.example.org/avatar/63a75a80e6b1f4adfdb04c1ca02e596c", [
{
"schemes": [
"http",
"https"
],
"host_suffix": ".gravatar.com",
"path_prefix": "/avatar/"
}
])
self.assertFalse(test2)
# Test against open redirect with valid URL in query params
test3 = is_trusted_url("https://github.com/SethFalco/?boop=https://secure.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50", [
{
"schemes": [
"http",
"https"
],
"host_suffix": ".gravatar.com",
"path_prefix": "/avatar/"
}
])
self.assertFalse(test3)
test4 = is_trusted_url("https://ui-avatars.com/api/blah", [
{
"schemes": [
"https"
],
"host_equals": "ui-avatars.com",
"path_prefix": "/api/"
},
{
"schemes": [
"http",
"https"
],
"host_suffix": ".gravatar.com",
"path_prefix": "/avatar/"
}
])
self.assertTrue(test4)

View File

@@ -5,7 +5,6 @@ Simple module providing reusable random_string function
import random
import string
from PIL import Image, ImageDraw
from urllib.parse import urlparse
def random_string(length=10):
@@ -113,42 +112,3 @@ def mm_ng(
)
return image
def is_trusted_url(url, url_filters):
"""
Check if a URL is valid and considered a trusted URL.
If the URL is malformed, returns False.
Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/events/UrlFilter
"""
(scheme, netloc, path, params, query, fragment) = urlparse(url)
for filter in url_filters:
if "schemes" in filter:
schemes = filter["schemes"]
if scheme not in schemes:
continue
if "host_equals" in filter:
host_equals = filter["host_equals"]
if netloc != host_equals:
continue
if "host_suffix" in filter:
host_suffix = filter["host_suffix"]
if not netloc.endswith(host_suffix):
continue
if "path_prefix" in filter:
path_prefix = filter["path_prefix"]
if not path.startswith(path_prefix):
continue
return True
return False

View File

@@ -34,7 +34,7 @@ from .ivataraccount.models import ConfirmedEmail, ConfirmedOpenId
from .ivataraccount.models import UnconfirmedEmail, UnconfirmedOpenId
from .ivataraccount.models import Photo
from .ivataraccount.models import pil_format, file_format
from .utils import is_trusted_url, mm_ng
from .utils import mm_ng
URL_TIMEOUT = 5 # in seconds
@@ -146,9 +146,7 @@ class AvatarImageView(TemplateView):
# Check for :// (schema)
if default is not None and default.find("://") > 0:
# Check if it's trusted, if not, reset to None
trusted_url = is_trusted_url(default, TRUSTED_DEFAULT_URLS)
if not trusted_url:
if not any(x in default for x in TRUSTED_DEFAULT_URLS):
print(
"Default URL is not in trusted URLs: '%s' ; Kicking it!" % default
)

2
ssh-pubkeys Normal file
View File

@@ -0,0 +1,2 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6t7d4wsHf/4Ymwo8gnqxsTM2BiqsqEJzuGOOI00uqQNI5s50oalsAjRBzLa4Lum8nmA6tJLf7uk/N0atkF/80x6g9n0VayJnXhGjVz/c2UNL2bPbO9J0Zx1Lrelr1QjlSq3Rf/VoWO2vf63UNW5VOXRCSmCT8UJFUh7eaPs+jXI9AMgSorEEGNSa/Be+bWDVR5Y7K9KT2XcUYZH5c6wASGIl3huscQDcMa/znaruER/21sk3/LAnhHVTjaEjXBbFrL+7mk4up+nlTEwOYupOkEn2CpKc8YuURH6GoVQ/HIYf7CPOKOrVAM3k43rbNb67u1yoHERM4ykMCUhsVCczR falko@home
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDnNQpIpD+b1ER1Gg0H+rSvWSg7M9aZIxHYNwWpuvpBOF95zzRbnkswABD1LobU43XLs1mUFca5Fmh+DU02PpnRnyYqzc16O3dFZbClre9Z1eNDcodQSVZqy0L8VM56qnUjD3NF7AExEwG6meSozQLluyHHrg4LnuSoQ2sOKeDSOdxkndE4SPlAwyogvYkglQlrFClxptQfCEH7zLu4f+Y8/ycUpSwSUxy/GCahWNyKQ9mGBkpU+04ZlLjstO0Xaa8KCBREn5KkHRfnk5kjJMv29fz1GRkLaOp0UnZjb6Srzx+LO+e0+wl7gS0ff9FJixEgS23lCYP3p4d8pduu9yX3 ofalk@work