15 Commits
v0.1 ... v2.0

Author SHA1 Message Date
565a91e4ec Remove uploadkeys encryption features
It doesn't really make sense to encrypt the keys, but store the secret
literally in the same directory. uploadkeys will now be stored in
plaintext. The branch `legacy` has the old code from before this commit.
2020-09-03 21:44:58 -05:00
3fcdaa2b10 Fix formatting of README.md 2020-09-02 21:52:13 -05:00
4309225185 Add Installation section to README.md
- Added Installation section to README.md
- Removed old Usage section
2020-09-02 21:43:31 -05:00
065296f84a Rename functions.py to functions.py.default
Since this is default settings and the user might want to customize
them, functions.py has been renamed. This also will prevent conflicts if
the user has updated their functions.py and then tries to pull.
2020-09-02 18:04:41 -05:00
841bb513d3 Allow easy customization of filename generation
Added a new file called functions.py which contains user-customizable
functions, instead of requiring the user to edit imgupload.py.
2020-09-02 17:14:28 -05:00
f0bb30a747 Change keygen.py to not require root
keygen.py now recommends that you run it as the user you want to have
ownership of secret.key and uploadkeys (such as www-data for nginx).
Then, if uploadkeys or secret.key don't exist, they will be created with
the correct ownership.
2020-09-02 14:26:57 -05:00
7fce3f57e9 Remove secrets from requirements.txt
On macOS, a dependency of secrets fails to install using pip. After
testing, it looks like the secrets module is not required.
2020-08-31 23:46:28 -05:00
a587040809 Bump cryptography from 2.8 to 3.1 (#2) 2020-09-01 04:41:50 +00:00
8a95dbb0fa Remove trailing whitespace from lines 2020-08-31 23:09:39 -05:00
a5a22b7c88 Remove UPLOADKEYS_CHMOD option due to keygen.py
Since keygen.py is run as root, uploadkeys is owned by root. This causes
issues when imgupload.py tries to chmod the uploadkeys file since it
doesn't have permissions to chmod it.
Solution: remove UPLOADKEYS_CHMOD option
2020-08-31 21:14:09 -05:00
7ccaafc6c6 Bugfixes in keygen.py
- Handle if uploadkeys becomes corrupted
- Disambiguate variable names
- Handle case where the uploadkeys file doesn't already exist
2020-08-31 20:32:00 -05:00
797bebb1a1 Fix ENCKEY_PATH check in configtest.py 2020-08-31 20:29:07 -05:00
08f9e13da0 Merge pull request #1 from BBaoVanC/dev
added encryption to uploadkeys and added a key generator
2020-08-31 17:13:24 -07:00
3d1304b3b0 added encryption to uploadkeys and added a key generator 2020-08-31 17:12:39 -07:00
4b624f3fed Ignore settings.py and add settings.py.default 2020-08-31 18:48:22 -05:00
7 changed files with 45 additions and 31 deletions

2
.gitignore vendored
View File

@ -132,3 +132,5 @@ dmypy.json
uploadkeys
savelog.log
uwsgi.log
settings.py
functions.py

View File

@ -1,4 +1,26 @@
# imgupload
Python Flask uWSGI application to receive and save images over POST requests.
![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/BBaoVanC/imgupload/master?color=purple) ![GitHub repo size](https://img.shields.io/github/repo-size/bbaovanc/imgupload?color=purple) ![GitHub All Releases](https://img.shields.io/github/downloads/bbaovanc/imgupload/total?color=purple) ![GitHub issues](https://img.shields.io/github/issues/bbaovanc/imgupload?color=purple) ![GitHub closed issues](https://img.shields.io/github/issues-closed/bbaovanc/imgupload?color=purple) ![GitHub](https://img.shields.io/github/license/bbaovanc/imgupload?color=purple)
This project is still in development. Use at your own risk!
### What is imgupload?
imgupload is a Flask + uWSGI application to serve as an all-purpose image/file uploader over POST requests.
### Installation
1. Clone the repository: `git clone https://github.com/BBaoVanC/imgupload.git`
2. Enter the imgupload directory: `cd imgupload`
3. Create a virtualenv: `python3 -m venv env`
4. Enter the virtualenv: `source env/bin/activate`
5. Install dependencies: `python3 -m pip install -r requirements.txt`
6. Run the Flask app
## Running the Flask app
### Using uWSGI
[https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html](https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html)
Instructions specific to imgupload are coming soon
### Using Flask development server
```shell
$ source env/bin/activate # if you haven't already entered the virtualenv
$ export FLASK_APP=imgupload.py
$ flask run
```

View File

@ -9,7 +9,6 @@ defaults = {
"ROOTURL": "https://img.bbaovanc.com/",
"SAVELOG": "savelog.log",
"SAVELOG_CHMOD": "0o644",
"UPLOADKEYS_CHMOD": "0o400",
"SAVELOG_KEYPREFIX": 4,
}
@ -19,7 +18,6 @@ deftypes = {
"ROOTURL": str,
"SAVELOG": str,
"SAVELOG_CHMOD": int,
"UPLOADKEYS_CHMOD": int,
"SAVELOG_KEYPREFIX": int,
}

8
functions.py.default Normal file
View File

@ -0,0 +1,8 @@
import string
import random
def generate_name():
chars = string.ascii_letters + string.digits # uppercase, lowercase, and numbers
name = ''.join((random.choice(chars) for i in range(8))) # generate name
return name

View File

@ -1,15 +1,13 @@
from flask import Flask, request, jsonify, abort, Response
from cryptography.fernet import Fernet
from flask_api import status
from pathlib import Path
import string
import random
import os
import datetime
import settings # app settings (such as allowed extensions)
ALPHANUMERIC = string.ascii_letters + string.digits # uppercase, lowercase, and numbers
import functions # custom functions
app = Flask(__name__) # app is the app
@ -21,15 +19,6 @@ def allowed_extension(testext):
return False
def generate_name(extension):
namefound = False
while not namefound:
fname = ''.join((random.choice(ALPHANUMERIC) for i in range(8))) + str(extension)
if not Path(fname).is_file():
namefound = True
return fname
def log_savelog(key, ip, savedname):
if settings.SAVELOG_KEYPREFIX > 0:
with open(settings.SAVELOG, "a+") as slogf:
@ -40,21 +29,16 @@ def log_savelog(key, ip, savedname):
slogf.write("[{0}] {1} - {2}\n".format(datetime.datetime.now(), ip, savedname))
os.chmod(settings.SAVELOG, settings.SAVELOG_CHMOD)
@app.route("/upload", methods = ["POST"])
def upload():
if request.method == "POST": # sanity check: make sure it's a POST request
print("Request method was POST!")
os.chmod("uploadkeys", settings.UPLOADKEYS_CHMOD)
print("Changed permissions of `uploadkeys`")
with open("uploadkeys", "r") as keyfile: # load valid keys
validkeys = keyfile.readlines()
validkeys = [x.strip("\n") for x in validkeys]
while "" in validkeys:
validkeys.remove("")
print("removed blank key")
print("Valid keys: {0}".format(validkeys))
print("Loaded validkeys")
if "uploadKey" in request.form: # if an uploadKey was provided
@ -63,7 +47,6 @@ def upload():
if "imageUpload" in request.files: # check if image to upload was provided
f = request.files["imageUpload"] # f is the image to upload
print("Found uploaded image")
else:
print("No image upload was found!")
return jsonify({'status': 'error', 'error': 'NO_IMAGE_UPLOADED'}), status.HTTP_400_BAD_REQUEST
@ -73,23 +56,23 @@ def upload():
return jsonify({'status': 'error', 'error': 'FILENAME_BLANK'}), status.HTTP_400_BAD_REQUEST
fext = Path(f.filename).suffix # get the uploaded extension
print("Uploaded file extensions is {0}".format(fext))
if allowed_extension(fext): # if the extension is allowed
fname = generate_name(fext) # generate file name
print("Generating file with extension {0}".format(fext))
fname = functions.generate_name() + fext # generate file name
print("Generated name: {0}".format(fname))
if f: # if the uploaded image exists
print("Uploaded image exists, obviously.")
print("Uploaded image exists")
f.save(os.path.join(settings.UPLOAD_FOLDER, fname)) # save the image
print("Saved to {0}".format(fname))
url = settings.ROOTURL + fname # construct the url to the image
if settings.SAVELOG != "/dev/null":
print("Saving to savelog")
log_savelog(request.form["uploadKey"], request.remote_addr, fname)
print("Logged message to savelog")
print("Returning json response")
return jsonify({'status': 'success', 'url': url, 'name': fname, 'uploadedName': f.filename}), status.HTTP_201_CREATED
else: # this shouldn't happen
print("Um... uploaded image is nonexistent..? Please report this error!")
print("Um... uploaded image... is nonexistent? Please report this error!")
return jsonify({'status': 'error', 'error': 'UPLOADED_IMAGE_FAILED_SANITY_CHECK_1'}), status.HTTP_400_BAD_REQUEST
else: # if the extension was invalid

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
Flask_API==2.0
Flask==1.1.2

View File

@ -1,7 +1,6 @@
UPLOAD_FOLDER = "/var/www/img"
UPLOAD_FOLDER = "/path/to/images"
ALLOWED_EXTENSIONS = [".png", ".jpg", ".jpeg", ".svg", ".bmp", ".gif", ".ico", ".webp"]
ROOTURL = "https://img.bbaovanc.com/"
ROOTURL = "https://example.com/"
SAVELOG = "savelog.log"
SAVELOG_CHMOD = 0o644
UPLOADKEYS_CHMOD = 0o600
SAVELOG_KEYPREFIX = 4