diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | db.py | 4 | ||||
-rwxr-xr-x | fbin.py | 65 | ||||
-rw-r--r-- | static/style.css | 3 | ||||
-rw-r--r-- | templates/help.tmpl | 18 |
5 files changed, 75 insertions, 17 deletions
@@ -1,4 +1,4 @@ *.swp *.pyc settings.py -/images +/files @@ -27,12 +27,14 @@ class File(Base): id = Column(Integer, primary_key = True) hash = Column(String, unique = True, index = True) + file_hash = Column(String, unique = True, index = True) filename = Column(String) date = Column(DateTime) user_id = Column(Integer, ForeignKey('users.id'), nullable = True) - def __init__(self, hash, filename, date, user_id = None): + def __init__(self, hash, file_hash, filename, date, user_id = None): self.hash = hash + self.file_hash = file_hash self.filename = filename self.date = date self.user_id = user_id @@ -20,6 +20,24 @@ class Application(object): return user + def get_user_by_name(self, username): + session = db.Session() + try: + return session.query(db.User).filter(db.User.username == username).one() + except db.NoResultFound: + return None + finally: + session.close() + + def get_user_by_id(self, uid): + session = db.Session() + try: + return session.query(db.User).filter(db.User.id == uid).one() + except db.NoResultFound: + return None + finally: + session.close() + def add_user(self, username, password): session = db.Session() try: @@ -44,14 +62,14 @@ class Application(object): return os.path.join(settings.file_directory, hash + os.path.splitext(file.filename)[1]) - def add_file(self, path, filename, user = None): + def add_file(self, path, filename, file_hash, user = None): hash = ''.join(random.choice(base62_alphabet) for x in xrange(5)) new_path = os.path.join(settings.file_directory, hash + os.path.splitext(filename)[1]) shutil.copyfile(path, new_path) session = db.Session() try: - file = db.File(hash, filename, datetime.datetime.utcnow(), user.id if user else None) + file = db.File(hash, file_hash, filename, datetime.datetime.utcnow(), user.id if user else None) session.add(file) session.commit() finally: @@ -74,20 +92,32 @@ class Application(object): def validate_cookie(self, cookie): if not cookie: return None - uid = int(cookie['uid'].value) + identifier = cookie['identifier'].value + if 'username' in cookie: + user = self.get_user_by_name(cookie['username'].value) + if not user: + return None + digest = hashlib.sha1(user.username + user.password).hexdigest() + return user if (digest == identifier) else None + + user = self.get_user_by_id(cookie['uid'].value) + if not user: + return None + + digest = hashlib.sha1(str(user.id) + user.password).hexdigest() + return user if (digest == identifier) else None + + def get_file_by_file_hash(self, file_hash): session = db.Session() try: - user = session.query(db.User).filter(db.User.id == uid).one() + return session.query(db.File).filter(db.File.file_hash == file_hash).one() except db.NoResultFound: return None finally: session.close() - digest = hashlib.sha1(str(uid) + user.password).hexdigest() - return user if (digest == identifier) else None - def file(self, environ, start_response, path): hash = path[1] if '.' in hash: @@ -116,13 +146,26 @@ class Application(object): temp.write(form.getvalue('file')) temp.flush() - hash = self.add_file(temp.name, filename, user) + m = hashlib.md5() + with open(temp.name) as f: + s = f.read(128) + while len(s): + m.update(s) + s = f.read(128) + file_hash = m.hexdigest() + + f = self.get_file_by_file_hash(file_hash) + # TODO: Currently users uploading existing files won't get their files added to their account. + if f: + hash = f.hash + else: + hash = self.add_file(temp.name, filename, file_hash, user) temp.close() - if 'redir' in form: - start_response('302 Found', [('Content-Type', 'text/html'), ('Location', '/f/{0}/{1}'.format(hash, filename))]) - return ['<a href="/f/{0}/{1}">{1}</a>'.format(hash, filename)] + if 'api' in form: + start_response('200 OK', [('Content-Type', 'text/plain')]) + return ['OK {hash}'.format(hash = hash)] else: start_response('200 OK', [('Content-Type', 'text/html')]) return str(templates.uploaded(searchList = { diff --git a/static/style.css b/static/style.css index f281482..e16b5b7 100644 --- a/static/style.css +++ b/static/style.css @@ -9,7 +9,8 @@ div#page-footer { background-color: #333; color: #666; height: 1em; padding: .5e ul { list-style-type: none; } li { margin-left: 1em; } p { margin-bottom: 1em; } -code { font-family: monospace; margin: 1em; display: block; } +code { font-family: monospace; } +blockquote { margin: 1em; display: block; } .error { color: red; } diff --git a/templates/help.tmpl b/templates/help.tmpl index 5dc096f..bdf95d4 100644 --- a/templates/help.tmpl +++ b/templates/help.tmpl @@ -3,9 +3,21 @@ #extends templates.base #def content <p>Usage: POST to <a href="$scheme://$host/u">$scheme://$host/u</a> with filedata given to "file" and original filename to "filename". - Login is sent by cookies with user id in "uid" and an identifier which is sha1(uid+sha1(password)).</p> + Login is sent by cookies with either: + <ul> + <li>user id in "uid" and an identifier which is sha1(uid+sha1(password))</li> + </ul> + or + <ul> + <li>username in "username" and an identifier which is sha1(username+sha1(password))</li> + </ul> + </p> <p>cURL example: - <code>curl -b 'uid=42; identifier=360b411581c3d516c8d55c290f039b144cea79ad' -F 'file=@image.png' -F 'filename=image.png' http://myhost/u</code> + <blockquote><code>curl -b 'uid=42; identifier=360b411581c3d516c8d55c290f039b144cea79ad' -F 'file=@image.png' -F 'filename=image.png' -F 'api=1' http://myhost/u</code></blockquote> Here user id is 42 and the password is "foobar". - If you get HTTP 417 responses, try adding:<code>-H 'Expect:'</code></p> + If you get HTTP 417 responses, try adding:<code>-H 'Expect:'</code>.</p> + <p>By adding the key-value pair "api=1" you will get machine-readable responses in the form: <code>response result</code> where <code>response</code> is either <code>ERROR</code> or <code>OK</code>, + and <code>result</code> is the file hash in the case of <code>OK</code>, or an error message in the case of <code>ERROR</code>. + The hash can be used to construct URLs in which the paths begin with <code>/f/hash</code> where <code>hash</code> is the hash received.</p> + <p>Any file extension an be appended to the hash, and for convenience the original filename (or whatever filename you prefer) can be appended after an additional slash after the hash.</p> #end def |