Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Added some config support, removing the need to hard code urls and salts #6

Open
wants to merge 8 commits into
from
View
54 README
@@ -15,12 +15,20 @@ Features:
-Users can change their own passwords
-Add users easily
+Requirements:
+
+ * http://webpy.org/
+ * Unix/Linx machine (currently requires crypt module)
+
Installation:
-Run Locally
python index.py (http://localhost:8080)
Not Recommend for daily usage
-Configure the webserver correctly to use webpy script
+ Move script to web server:
+ tar -zcvf myuploader.tgz index.py static/ templates/ web/
+
***Lighttpd Example***
fastcgi.server = (
@@ -39,33 +47,31 @@ Installation:
url.rewrite-once = (
"^/uploader/(.*)$" => "/uploader.py/$1"
)
-
-
- -Create Sqlite Database:
- create table sessions (
- session_id char(128) UNIQUE NOT NULL,
- atime timestamp NOT NULL default current_timestamp,
- data text
- );
- create table users (
- id INTEGER PRIMARY KEY,
- name VARCHAR(20) NOT NULL,
- password VARCHAR(20) NOT NULL,
- credits INTEGER,
- exprdate DATETIME,
- usertype CHAR(5) NOT NULL
- );
-
- # Username: admin, Password: admin, Usertype: admin
- insert INTO 'users' (name, password, usertype) values ('admin', 'tdlasp2ru0PJ6', 'admin');
-
- To generate the password hash: python -c "import crypt; print crypt.crypt('yourPassword', 'td')"
+
+ Depending on server may want to create a .htaccess file to protect database/config file and auto defaulting to application URL:
+
+ # Set the default handler.
+ DirectoryIndex index.fcgi/
- Alternatively use the example.db (username: admin, password: admin)
+ # deny access to user database
+ <FilesMatch "app.db|uploader.ini">
+ Order deny,allow
+ Deny from all
+ </FilesMatch>
+
+ NOTE web.py web/wsgi.py also need to be edited to NOT pass any params other than function into flups.WSGIServer() for runfcgi also updated application.py to call runfcgi()
- Rename the database to app.db
- -Configure some simple variables in index.py
+ - Run `python index.py resetadmin` this will create the app.db database
+ and prompt for the admin password.
+
+ -Configure some simple variables. Either create `uploader.ini` with contents like:
+
+ [config]
+ uploadpath: /tmp
+ uploadurl: http://www.example.com/uploads
+
+ Or in index.py
uploadpath = physical path where all uploads will be stored - ex: /srv/http/example.com/uploads/
uploadurl = the url to access all uploaded files - ex: http://example.com/uploads/
View
Binary file not shown.
View
105 index.py
@@ -1,22 +1,44 @@
#!/usr/bin/env python
+# -*- coding: us-ascii -*-
+# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
+#
-import web
-from web import form
-import sqlite3
-import crypt
import os
+import sys
import cgi
+import random
+import string
+import getpass
from datetime import datetime
+import ConfigParser
import itertools
+import sqlite3
+
+import web
+from web import form
+import crypt # FIXME consider replacing with http://pypi.python.org/pypi/cryptacular/ which is portable and more secure in the off change the hashes are exposed
#Must be disabled, otherwise sessions break!!!
web.config.debug = False
# Configuration Settings
-uploadpath = '/home/http/pyther.net/uploads' #Physical Path to file uploads on file system
-uploadurl = 'http://pyther.net/uploads' #Web Address to said uploads
+config_filename = 'uploader.ini' # TODO may need full pathname
+config = ConfigParser.ConfigParser()
+config.read(config_filename)
+config_dict = {}
+try:
+ for key in config.options('config'):
+ config_dict[key] = config.get('config', key)
+except ConfigParser.NoSectionError:
+ pass
+
+
+uploadpath = config_dict.get('uploadpath') or '/home/http/pyther.net/uploads' #Physical Path to file uploads on file system
+uploadurl = config_dict.get('uploadurl') or 'http://pyther.net/uploads' #Web Address to said uploads
+database_name = config_dict.get('database_name') or "app.db"
#Values must be in bytes
+# FIXME TODO pick up from config file or database
MaxSize=(20 * 1024 * 1024) # 20MB
MaxSizeAdmin=0 #0 for Administrators
@@ -40,7 +62,39 @@
web.config.session_parameters['expired_message'] = 'Session Expired... Please reload the page and login in again.' #Error message when session expires
#Initalizes and stores session information in sqlite database
-db = web.database(dbn="sqlite", db="app.db")
+# sqlite3 specific code
+db = sqlite3.connect(database_name)
+# TODO DDL only if empty..
+c = db.cursor()
+try:
+ c.execute("""
+ create table sessions (
+ session_id char(128) UNIQUE NOT NULL,
+ atime timestamp NOT NULL default current_timestamp,
+ data text
+ )
+ """)
+except sqlite3.OperationalError:
+ # Assume table already exists
+ pass
+try:
+ c.execute("""
+ create table users (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(20) NOT NULL,
+ password VARCHAR(20) NOT NULL,
+ credits INTEGER,
+ exprdate DATETIME,
+ usertype CHAR(5) NOT NULL
+ )
+ """)
+except sqlite3.OperationalError:
+ # Assume table already exists
+ pass
+c.close()
+db.commit()
+db.close()
+db = web.database(dbn="sqlite", db=database_name)
store = web.session.DBStore(db, 'sessions')
session = web.session.Session(app, store, initializer={'login': 0,'userType':'anonymous'})
@@ -129,14 +183,19 @@ def checkChangePasswd(i):
password=i.password
return checkpassword(username,password)
+def getsalt(chars = string.letters + string.digits):
+ # generate a random 2-character 'salt'
+ return random.choice(chars) + random.choice(chars)
+
def checkpassword(username,password):
- typed_password = crypt.crypt(password, 'td') #Encrypted Typed Password
user=list(db.select('users', dict(name=username), where="name = $name"))
if len(user) == 1:
user=user[0]
else:
raise DBEntry('Too Many!')
db_password=user.get('password') #Encrypted Password in Database
+ temp_salt = db_password[:2]
+ typed_password = crypt.crypt(password, temp_salt) #Encrypted Typed Password
return typed_password == db_password
# Database lookups + writes
@@ -394,7 +453,7 @@ def POST(self):
if f.validates():
# If the form validates store variables locally and insert them into the database
username = f.d.username.lower()
- password = crypt.crypt(f.d.password, 'td')
+ password = crypt.crypt(f.d.password, getsalt())
credits = f.d.credits
date = datetime(int(f.d.year), int(f.d.month), int(f.d.day))
userType=f.d.uType
@@ -476,7 +535,7 @@ def POST(self):
#Change Password if one was entered
if password:
- newPass = crypt.crypt(password, 'td') #Encrypted Typed Password
+ newPass = crypt.crypt(password, getsalt()) #Encrypted Typed Password
db.update('users', where="id=$id", password=newPass, vars=dict(id=id) )
else:
#Fill in the form with the values that were submitted
@@ -552,7 +611,7 @@ def POST(self):
f = changePass_form()
if f.validates():
username = session.username
- password = crypt.crypt(f.d.newPass1, 'td') #Encrypted Typed Password
+ password = crypt.crypt(f.d.newPass1, getsalt()) #Encrypted Typed Password
db.update('users', where="name=$username", password=password, vars=dict(username=username))
else:
return render.password(f,'')
@@ -603,6 +662,26 @@ def POST(self):
url=uploadurl+'/'+session.username+"/"+filename
return render.upResult(filename, url)
-
-if __name__ == "__main__": app.run()
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+
+ if 'resetadmin' in argv:
+ # DDL? See earlier in script
+ # add option delete (all) users?
+ db.delete('users', where="name='admin'")
+ new_passwd = getpass.getpass('Enter new admin password: ')
+ new_passwd = crypt.crypt(new_passwd, getsalt())
+ username = 'admin'
+ user_type = 'admin'
+ db.insert('users', name=username, password=new_passwd, usertype=user_type)
+ else:
+ app.run()
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())