added url validation to all server requests
This commit is contained in:
parent
7fd5fca0cf
commit
d48fe26a35
@ -6,6 +6,7 @@ from gettext import gettext as _
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
@ -59,7 +60,9 @@ class CookBookApp(Integration):
|
|||||||
|
|
||||||
if len(images) > 0:
|
if len(images) > 0:
|
||||||
try:
|
try:
|
||||||
response = requests.get(images[0])
|
url = images[0]
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
self.import_recipe_image(recipe, BytesIO(response.content))
|
self.import_recipe_image(recipe, BytesIO(response.content))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('failed to import image ', str(e))
|
print('failed to import image ', str(e))
|
||||||
|
@ -5,6 +5,7 @@ from io import BytesIO
|
|||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
@ -64,7 +65,9 @@ class Cookmate(Integration):
|
|||||||
|
|
||||||
if recipe_xml.find('imageurl') is not None:
|
if recipe_xml.find('imageurl') is not None:
|
||||||
try:
|
try:
|
||||||
response = requests.get(recipe_xml.find('imageurl').text.strip())
|
url = recipe_xml.find('imageurl').text.strip()
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
self.import_recipe_image(recipe, BytesIO(response.content))
|
self.import_recipe_image(recipe, BytesIO(response.content))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('failed to import image ', str(e))
|
print('failed to import image ', str(e))
|
||||||
|
@ -5,6 +5,7 @@ from io import BytesIO
|
|||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from cookbook.helper.image_processing import get_filetype
|
from cookbook.helper.image_processing import get_filetype
|
||||||
@ -123,7 +124,9 @@ class RecetteTek(Integration):
|
|||||||
self.import_recipe_image(recipe, BytesIO(import_zip.read(image_file_name)), filetype=get_filetype(image_file_name))
|
self.import_recipe_image(recipe, BytesIO(import_zip.read(image_file_name)), filetype=get_filetype(image_file_name))
|
||||||
else:
|
else:
|
||||||
if file['originalPicture'] != '':
|
if file['originalPicture'] != '':
|
||||||
response = requests.get(file['originalPicture'])
|
url = file['originalPicture']
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
if imghdr.what(BytesIO(response.content)) is not None:
|
if imghdr.what(BytesIO(response.content)) is not None:
|
||||||
self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
|
self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
|
||||||
else:
|
else:
|
||||||
|
@ -2,6 +2,7 @@ import json
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
|
|
||||||
from cookbook.helper.ingredient_parser import IngredientParser
|
from cookbook.helper.ingredient_parser import IngredientParser
|
||||||
from cookbook.integration.integration import Integration
|
from cookbook.integration.integration import Integration
|
||||||
@ -51,7 +52,9 @@ class RecipeSage(Integration):
|
|||||||
|
|
||||||
if len(file['image']) > 0:
|
if len(file['image']) > 0:
|
||||||
try:
|
try:
|
||||||
response = requests.get(file['image'][0])
|
url = file['image'][0]
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
self.import_recipe_image(recipe, BytesIO(response.content))
|
self.import_recipe_image(recipe, BytesIO(response.content))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('failed to import image ', str(e))
|
print('failed to import image ', str(e))
|
||||||
|
@ -4,6 +4,8 @@ import os
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
|
|
||||||
from cookbook.models import Recipe, RecipeImport, SyncLog
|
from cookbook.models import Recipe, RecipeImport, SyncLog
|
||||||
from cookbook.provider.provider import Provider
|
from cookbook.provider.provider import Provider
|
||||||
|
|
||||||
@ -104,7 +106,9 @@ class Dropbox(Provider):
|
|||||||
recipe.link = Dropbox.get_share_link(recipe)
|
recipe.link = Dropbox.get_share_link(recipe)
|
||||||
recipe.save()
|
recipe.save()
|
||||||
|
|
||||||
response = requests.get(recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.'))
|
url = recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.')
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
|
|
||||||
return io.BytesIO(response.content)
|
return io.BytesIO(response.content)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import tempfile
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
import webdav3.client as wc
|
import webdav3.client as wc
|
||||||
from cookbook.models import Recipe, RecipeImport, SyncLog
|
from cookbook.models import Recipe, RecipeImport, SyncLog
|
||||||
from cookbook.provider.provider import Provider
|
from cookbook.provider.provider import Provider
|
||||||
@ -92,6 +93,7 @@ class Nextcloud(Provider):
|
|||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if validators.url(url, public=True):
|
||||||
r = requests.get(
|
r = requests.get(
|
||||||
url,
|
url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
|
@ -6,6 +6,7 @@ import uuid
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import validators
|
||||||
from PIL import UnidentifiedImageError
|
from PIL import UnidentifiedImageError
|
||||||
from annoying.decorators import ajax_request
|
from annoying.decorators import ajax_request
|
||||||
from annoying.functions import get_object_or_None
|
from annoying.functions import get_object_or_None
|
||||||
@ -14,7 +15,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.contrib.postgres.search import TrigramSimilarity
|
from django.contrib.postgres.search import TrigramSimilarity
|
||||||
from django.core.exceptions import FieldError, ValidationError
|
from django.core.exceptions import FieldError, ValidationError
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db.models import (Case, Count, Exists, F, IntegerField, OuterRef, ProtectedError, Q,
|
from django.db.models import (Case, Count, Exists, OuterRef, ProtectedError, Q,
|
||||||
Subquery, Value, When)
|
Subquery, Value, When)
|
||||||
from django.db.models.fields.related import ForeignObjectRel
|
from django.db.models.fields.related import ForeignObjectRel
|
||||||
from django.db.models.functions import Coalesce, Lower
|
from django.db.models.functions import Coalesce, Lower
|
||||||
@ -24,7 +25,6 @@ from django.urls import reverse
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from icalendar import Calendar, Event
|
from icalendar import Calendar, Event
|
||||||
from recipe_scrapers import NoSchemaFoundInWildMode, WebsiteNotImplementedError, scrape_me
|
|
||||||
from requests.exceptions import MissingSchema
|
from requests.exceptions import MissingSchema
|
||||||
from rest_framework import decorators, status, viewsets
|
from rest_framework import decorators, status, viewsets
|
||||||
from rest_framework.exceptions import APIException, PermissionDenied
|
from rest_framework.exceptions import APIException, PermissionDenied
|
||||||
@ -34,6 +34,7 @@ from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ViewSetMixin
|
from rest_framework.viewsets import ViewSetMixin
|
||||||
from treebeard.exceptions import InvalidMoveToDescendant, InvalidPosition, PathOverflow
|
from treebeard.exceptions import InvalidMoveToDescendant, InvalidPosition, PathOverflow
|
||||||
|
from validators import ValidationFailure
|
||||||
|
|
||||||
from cookbook.helper.HelperFunctions import str2bool
|
from cookbook.helper.HelperFunctions import str2bool
|
||||||
from cookbook.helper.image_processing import handle_image
|
from cookbook.helper.image_processing import handle_image
|
||||||
@ -43,7 +44,6 @@ from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, Cus
|
|||||||
group_required)
|
group_required)
|
||||||
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
|
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
|
||||||
from cookbook.helper.recipe_url_import import get_from_scraper
|
|
||||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
|
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
|
||||||
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, ExportLog, Food,
|
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, ExportLog, Food,
|
||||||
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
|
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
|
||||||
@ -781,7 +781,9 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
|||||||
filetype = mimetypes.guess_extension(serializer.validated_data['image'].content_type) or filetype
|
filetype = mimetypes.guess_extension(serializer.validated_data['image'].content_type) or filetype
|
||||||
elif 'image_url' in serializer.validated_data:
|
elif 'image_url' in serializer.validated_data:
|
||||||
try:
|
try:
|
||||||
response = requests.get(serializer.validated_data['image_url'])
|
url = serializer.validated_data['image_url']
|
||||||
|
if validators.url(url, public=True):
|
||||||
|
response = requests.get(url)
|
||||||
image = File(io.BytesIO(response.content))
|
image = File(io.BytesIO(response.content))
|
||||||
filetype = mimetypes.guess_extension(response.headers['content-type']) or filetype
|
filetype = mimetypes.guess_extension(response.headers['content-type']) or filetype
|
||||||
except UnidentifiedImageError as e:
|
except UnidentifiedImageError as e:
|
||||||
@ -1188,7 +1190,13 @@ def recipe_from_source(request):
|
|||||||
# in manual mode request complete page to return it later
|
# in manual mode request complete page to return it later
|
||||||
if url:
|
if url:
|
||||||
try:
|
try:
|
||||||
|
if validators.url(url, public=True):
|
||||||
data = requests.get(url, headers=external_request_headers).content
|
data = requests.get(url, headers=external_request_headers).content
|
||||||
|
else:
|
||||||
|
return JsonResponse({
|
||||||
|
'error': True,
|
||||||
|
'msg': _('Invalid Url')
|
||||||
|
}, status=400)
|
||||||
except requests.exceptions.ConnectionError:
|
except requests.exceptions.ConnectionError:
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
'error': True,
|
'error': True,
|
||||||
@ -1199,6 +1207,7 @@ def recipe_from_source(request):
|
|||||||
'error': True,
|
'error': True,
|
||||||
'msg': _('Bad URL Schema.')
|
'msg': _('Bad URL Schema.')
|
||||||
}, status=400)
|
}, status=400)
|
||||||
|
|
||||||
recipe_json, recipe_tree, recipe_html, recipe_images = get_recipe_from_source(data, url, request)
|
recipe_json, recipe_tree, recipe_html, recipe_images = get_recipe_from_source(data, url, request)
|
||||||
if len(recipe_tree) == 0 and len(recipe_json) == 0:
|
if len(recipe_tree) == 0 and len(recipe_json) == 0:
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
|
@ -43,3 +43,4 @@ python-ldap==3.4.0
|
|||||||
django-auth-ldap==4.0.0
|
django-auth-ldap==4.0.0
|
||||||
pytest-factoryboy==2.1.0
|
pytest-factoryboy==2.1.0
|
||||||
pyppeteer==1.0.2
|
pyppeteer==1.0.2
|
||||||
|
validators==0.19.0
|
Loading…
Reference in New Issue
Block a user