I have an ImageField in one of my Django models. Each of these images has a user (or group of users) who have access to them; no other users should be able to see them.
The ImageField stores the image file in the media root. Any web request for that image via the image path) bypass django and get served directly by Apache.
How do I ensure that only the users that are authorized to request the images can actually get them?
add new view for serve image and store image in other path, apache cant server new path
now in new view check group of user serve image
and if not your user send 403
#login_required
def serve_file(request, context):
if <check if they have access to the file>:
filename = "/var/www/myfile.xyz"
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition']='attachment;filename="%s"'%filename
response["X-Sendfile"] = filename
response['Content-length'] = os.stat("debug.py").st_size
return response
return <error state>
Related
I cant seem to understand how is it possible that for GCS the authenticated URL shows a different image then the public URL ?
Im uploading the images via a python django script
def upload_to_cloud(blob_name, file_obj):
file_type = imghdr.what(file_obj)
blob_name = str(blob_name) + '.' + file_type # concatenate string to create 'file_name.format'
stats = storage.Blob(bucket=bucket, name=blob_name).exists(client) # check if logo with the same reg.nr exists
if stats is True: # if exists then delete before uploading new logo
storage.Blob(bucket=bucket, name=blob_name).delete()
blob = bucket.blob(blob_name)
blob.upload_from_file(file_obj=file_obj, content_type=f'image/{file_type}')
path = blob.public_url
return path
class CompanyProfile(SuccessMessageMixin, UpdateView): # TODO why company logo differs from the one in ads_list?
model = Company
form_class = CompanyProfileCreationForm
def form_valid(self, form):
"""
Check if user uploaded a new logo. If yes
then upload the new logo to google cloud
"""
if 'logo' in self.request.FILES:
blob_name = self.request.user.company.reg_nr # get company registration number
file_obj = self.request.FILES['logo'] # store uploaded file in variable
form.instance.logo_url = upload_to_cloud(blob_name, file_obj) # update company.logo_url with path to uploaded file
company = Company.objects.get(pk=self.request.user.company.pk)
company.save()
return super().form_valid(form)
else:
return super().form_valid(form)
Any ideas on what Im doing wrong and how its even possible? The file that I actually uploaded is the one under authenticated url. The file thats under public url is a file that I uploaded for a different blob
EDIT
Im adding screenshot of the different images because after some time the images appear to be the same as they should be. Some people are confused by this and comment that the images are the same after all
Public URL
Authenticated URL
Note that caching issue is ruled out since I sent the public URL to my friend and he also saw that the image is the HTML text although the image in the authenticated URL (the correct image) was a light bulb. He also noted that the URL preview in fb messenger showed the light bulb image but when he actually opened the URL the HTML text image appeared
This problem persists in case a file is uploaded with the same blob name. This happens regardless if its overwritten by gcs or if I previously execute blob delete function and then create a new file with the same name as the deleted blob.
In general the same object will be served by storage.googleapis.com and storage.cloud.google.com.
The only exception is if there is some caching (either in your browser, in a proxy, with Cloud CDN or in GCS). If you read the object via storage.cloud.google.com before uploading a new version, then reading after by storage.cloud.google.com may serve the old version while storage.googleapis.com returns the new one. Caching can also be location dependent.
If you can't allow an hour of caching, set Cache control to no-cache.
I'm using DRF for backend and React for frontend.
In DRF I return link to my local saved file.
Django application takes 8080 port and react 8000.
And when I create Request from Frontend, DRF return path to file with localhost:8000/media/...
I need localhost:8080/media/...
enter image description here
This may be because your backend responded with /media/<file_name> because of this your frontend will add http://localhost:8000/ before the file response.
If you are working in the local environment then you have to change media response by joining your backend URL with file response.
for your solution:
Add BACKEND_URL in your DRF settings as http://localhost:8080/
in the model which stores media file add a #property
class TempModel(models.Model):
file = models.FileField()
#property
def get_file_url(self):
from urllib.parse import urljoin
from django.conf import settings
return urljoin(settings.BACKEND_URL, self.file.url
Add get_file_url in your serializer and use it as the source to the file. OR change your serializer as below so that the response will change in the file field automatically.
class TempModelSerializer(serializers.ModelSerializer):
file = serializers.URLField(sourc="get_file_url", read_only=True)
# other part of the serializer
NOTE: if you use the last option of serializer, make sure you can upload the file from the same API or for better reason change the API to add or update files only. but it is up to your system architecture.
I need to save an image on Amazon WS S3 using Django.
I have this code:
try:
img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urllib2.urlopen(urlImageTo Download).read())
img_temp.flush()
p.image.save('image.jpg', File(img_temp))
p.save() //P is an ImageField
except urllib2.HTTPError:
continue
I integrated django-storages to save directly the image in Amazon S3.
I have to save the image during a request (in the request I have an URL of an image that I have to download it and resave in Amazon S3) but I think that I can to have this line:
p.image.save('image.jpg', File(img_temp))
asynchronous.
In this case I can return immediately the response of my request while I can save the image on S3
How can I have this? Is Possible?
I am hosting some video files in rackspace cloud files, and each user is allowed to download the files that are assigned to them.
Because of the file sizes it is not feasible to buffer the object in the webserver(webfaction)
I tried a redirect to the file, with Content-Disposition set to attachment, but to no avail.
What kind of options do I have, if any?
Ideally the file download would pop as coming from my domain after clicking a link that points to something like example.com/video/42/download/ so I can handle authentication ect. but im not sure how to structure my view for that to happen.
You are probably best served by using an HttpResponseRedirect unless there is something I am misunderstanding...?
# urls.py
from django.http import HttpResponseRedirect
url(r'^applications/(?P<id>\d+)/image\.png$', 'core.views.serve_image', name='image'),
This will serve a view at http://localhost/application/12345/image.png.
# core/views.py
def serve_application_image(request, id):
# redirect to temp_url
application = Application.objects.get(id=id)
return HttpResponseRedirect(application.image.temp_url)
And this will redirect users that hit that URL to the Rackspace URL. It can work for embedding videos, images, etc, in html <img> tags and such. Browser clients will be able to see the redirected URL (at rackcdn.com).
I have configured my apps to serve a temp_url property that expires after 15 minutes. The temporary URL is created for the CDN at Rackspace.com and their documentation may be out of the scope for this question so I'll leave it off for now... but the code I use to sub-class ImageField to serve image attributes with the .temp_url code follows:
import hmac
from hashlib import sha1
from time import time
class ImageFieldFile_With_Temp_Url(ImageFieldFile):
#property
def temp_url(self):
container_name, file_name = (self.storage.container.name, self.name)
key = settings.CUMULUS['CUSTOM__X_ACCOUNT_META_TEMP_URL_KEY']
public_url = settings.CUMULUS['CUSTOM__X_STORAGE_URL']
method = 'GET'
expires = int(time() + settings.CUMULUS['CUSTOM__X_TEMP_URL_TIMEOUT'])
url = '%s/%s/%s' % (public_url, container_name, file_name)
base_url, object_path = url.split('/v1/')
object_path = '/v1/' + object_path
hmac_body = '%s\n%s\n%s' % (method, expires, object_path)
sig = hmac.new(key, hmac_body, sha1).hexdigest()
return '%s%s?temp_url_sig=%s&temp_url_expires=%s' % (base_url, object_path, sig, expires)
class ImageField_With_Temp_Url(models.ImageField):
attr_class = ImageFieldFile_With_Temp_Url
models.ImageField = ImageField_With_Temp_Url
Note that I am using the django-cumulus project in this approach.
Importing this function anywhere at the top of your models.py will extend ImageField with a new temp_url property (since I assign it to models.ImageField ...).
I'm developing a web application in Django, and one of its features is adding new articles with a photo.
My Article model class contains models.FileField. I use S3BotoStorage as DEFAULT_FILE_STORAGE (Amazon S3).
Users can add a photo to an article in two ways:
1) Upload a photo from disk (by using input type=file)
2) Paste URL to existing photo online
If users uses option 1), everything works. I get uploaded file in view from request.FILES dictionary and assing it to FileField in Article object. The photo is uploaded to S3.
But when user pastes URL to a photo, the first thing I have to do in view is to download this photo. I do it by using function:
def downloadPhotoFromURL(url):
try:
img = urllib.urlretrieve(url)[0]
return img
except Exception:
return None
Then I save this image to FileField in model, so my whole code responsible for downloading image, and uploading it to S3 is like this:
articleImg = downloadPhotoFromURL(url)
f = File(open(articleImg), 'rb')
newArticle.image.save('tmp', f)
In this situation, I cannot upload it to S3 and after 2 minutes I'm receiving BotoServerError: 400 Bad Request. Unfortunately I don't have any other information why this request is bad. Any idea what can be going wrong? By the time I saved an image to model, I had saved a model, so model exists when I try to upload photo to S3.