Help improve my file upload method (Pyramid framework) - python

Currently, I am using the following method for uploading files (via HTML form) in Pyramid.
if request.params.get('form.submitted'):
upload_directory = os.getcwd() + '/myapp/static/uploads/'
my_file = request.POST.get('thumbnail')
saved_file = str(upload_directory) + str(my_file.filename)
perm_file = open(saved_file, 'w')
shutil.copyfileobj(my_file.file, perm_file)
my_file.file.close()
perm_file.close()
I am just wondering, is this a good way of saving file uploads, are there any security concerns with my method? How else can I improve my method. Thanks.

You'll want to use something like werkzug's safe_join rather than just adding the upload directory to the given file name. An attacker could create a POST with a filename of ../../../some/important/path and cause this script to overwrite some file outside of your upload_directory.

Related

How can I specify the exact folder IN STREAMLIT for the uploaded file to be saved to?

I am trying to create a simple GUI with streamlit and python for my aspect-based sentiment analysis project, the user should be able to upload a .txt file so that I can run the model on that file. I already created the widget for uploading a file. My question is:
The uploaded file should be added to a specific folder, how can I specify an exact location for the uploaded file to be saved?
uploaded_file = st.file_uploader('FILE UPLOAD')
(This is the code for the upload widget)
The file_uploader function does not save the file to disk, it writes to a BytesIO buffer.
The UploadedFile class is a subclass of BytesIO, and therefore it is “file-like”. This means you can pass them anywhere where a file is expected.
https://docs.streamlit.io/en/stable/api.html?highlight=file_uploader#streamlit.file_uploader
If you want to save the result as a file, use the standard Python file io capabilities:
with open(filename, "wb") as f:
f.write(buf.getbuffer())
To add to what #RandyZwitch said you can use this function to save to a directory of your choice (directory/folder "tempDir")
def save_uploaded_file(uploadedfile):
with open(os.path.join("tempDir",uploadedfile.name),"wb") as f:
f.write(uploadedfile.getbuffer())
return st.success("Saved file :{} in tempDir".format(uploadedfile.name))
And apply the function below your uploaded file like below
datafile = st.file_uploader("Upload CSV",type=['csv'])
if datafile is not None:
file_details = {"FileName":datafile.name,"FileType":datafile.type}
df = pd.read_csv(datafile)
st.dataframe(df)
# Apply Function here
save_uploaded_file(datafile)
You can define path like this:
from pathlib import Path
path = "C:/Projects/ex1/your_file"
file_path = Path(path)
uploaded_file = st.file_uploader(file_path)

Python Django : Creating file object in memory without actually creating a file

I have an endpoint where I want to collect the response data and dump it into a file on S3 like this - https://stackoverflow.com/a/18731115/4824482
This is how I was trying to do it -
file_obj = open('/some/path/log.csv', 'w+')
file_obj.write(request.POST['data'])
and then passing file_obj to the S3 related code as in the above link.
The problem is that I don't have permissions to create a file on the server. Is there any way I can create a file object just in memory and then pass it to the S3 code?
Probably that's duplicate question of How to upload a file to S3 without creating a temporary local file. You would find best suggestion by checking out answers to that question.
Shortly the answer is code below:
from boto.s3.key import Key
k = Key(bucket)
k.key = 'yourkey'
k.set_contents_from_string(request.POST['data'])
Try tempfile https://docs.python.org/2/library/tempfile.html
f = tempfile.TemporaryFile()
f.write(request.POST['data'])

Flask-Uploads always throwing 'UploadNotAllowed' error even with no constraints

Flask-uploads has something called UploadSet which is described as a "single collection of files". I can use this upload set to save my file to a predefined location. I've defined my setup:
app = Flask(__name__)
app.config['UPLOADS_DEFAULT_DEST'] = os.path.realpath('.') + '/uploads'
app.config['UPLOADED_PHOTOS_ALLOW'] = set(['png', 'jpg', 'jpeg'])
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
# setup flask-uploads
photos = UploadSet('photos')
configure_uploads(app, photos)
#app.route('/doit', method=["POST"])
def doit():
myfile = request.files['file']
photos.save(myfile, 'subfolder_test', 'filename_test')
return ''' blah '''
This should save to ./uploads/photos/subfolder_test/filename_test.png
My test image is: 2.6MB and is a png file. When I upload this file, I get the error:
...
File "/home/btw/flask/app.py", line 57, in doit
photos.save(myfile, 'subfolder_test', 'filename_test')
File "/usr/local/lib/python2.7/dist-packages/flaskext/uploads.py", line 388, in save
raise UploadNotAllowed()
UploadNotAllowed
However it doesn't say exactly what is not allowed. I have also tried removing all constraints, but the app still throws this error. Why?
EDIT:
Okay, so I figured out that it's not actually the constraints that is causing the problem. It is the subfolder and/or the filename that is causing the problem:
# This works
# saves to: ./uploads/photos/filename_test.png
photos.save(myfile)
But I want to save to my custom location ./uploads/photos/<custom_subdir>/<custom_filename>. What is the correct way of doing this?
You need to give your filename_test the extension as well
photos.save(myfile, 'subfolder_test', 'filename_test.png')
The UploadSet checks the extension on the new file name and will throw the exception if the new extension is not allowed.
Since you are not giving the new file an extension, it does not recognize it.
You can add a dot to file's name, then the file's extension will be appended.
photos.save(myfile, 'subfolder_test', 'filename_test' + '.')
save(storage, folder=None, name=None)
Parameters:
storage – The uploaded file to save.
folder – The subfolder within the upload set to save to.
name – The name to save the file as. If it ends with a dot, the file’s extension will be appended to the end.

Python: Use Dropbox API - Save .ODT File

I'm using Dropbox API with Python. I don't have problems with Dropbox API, I make all the authentification steps without problems.
When I use this code:
pdf_dropbox = client.get_file('/Example.pdf')
new_file = open('/home/test.pdf','w')
new_file.write(pdf_dropbox.read())
I generate a file in the path /home/test.pdf, it's a PDF file and the content is displayed same as original.
But when I try same code with an .odt file, it fails generating the new file:
odt_dropbox = client.get_file('/Example.odt')
new_file = open('/home/test_odt.odt','w')
new_file.write(odt_dropbox.read())
This new file test_odt.odt has errors and I can't see it's content.
# With this instruction I have the content of the odt file inside odt_dropbox
odt_dropbox = client.get_file('/Example.odt')
Wich is the best way to save the content of an odt file ?
Is there a better way to write LibreOffice files ?
I'd appreciate any helpfull information,
Thanks
Solved, I forgot 2 things:
Open the file for binary writing wb instead of w
new_file = open('/home/test_odt.odt','wb')
Close the file after creation: new_file.close() to make the flush
Full Code:
odt_dropbox = client.get_file('/Example.odt')
new_file = open('/home/test_odt.odt','wb')
new_file.write(odt_dropbox.read())
new_file.close()

Django : Write a session data to a file and let the user download the data

Need Help on how to write session contents to a file in static directory in django, so that it can be served to the user.
I have some huge session data. I want to store it in a file. Then serve it back to user.
I have no idea how to do it. Can you please help me on this ?
Thanks,
Bala.
# mastazi, i did all research and without any luck came to SOF.
Here is a peiece of code i tried .
xml = request.session.get('content')
fileName = request.session['search'] + '.xml'
path = (/pathto/file/)
response = HttpResponse(FileWrapper(xml.read()), content_type='text/xml')
response['Content-Disposition'] = 'attachment; filename=%s'%fileName
I even tried to write the file to static folder ..
Then tried to access it directly. Its not working. There is some issue. I tried redirecting the output to the file path. But nothing works.
THanks

Categories