From e5aa2a49f40d9c06bd64a8ecd6a3fcc2a09dd6fd Mon Sep 17 00:00:00 2001 From: sponge Date: Fri, 14 Sep 2012 00:25:01 +0000 Subject: [PATCH] Add a more secure netDb app. --- netdb.i2p2/fixedapp.py | 203 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 netdb.i2p2/fixedapp.py diff --git a/netdb.i2p2/fixedapp.py b/netdb.i2p2/fixedapp.py new file mode 100644 index 00000000..5d11dcb2 --- /dev/null +++ b/netdb.i2p2/fixedapp.py @@ -0,0 +1,203 @@ +# +# Required software: +# sqlite3 3.6.23.1 or newer +# http://www.sqlite.org/ +# unixodbc +# http://www.unixodbc.org/ +# pyodbc-3.0.6 or newer +# http://www.ch-werner.de/sqliteodbc/ +# werkzeug +# http://werkzeug.pocoo.org/ +# python 2.6 or 2.7 +# http://python.org/ +# + + +# Modify as needed, or use a symlink. +netdbdir = 'netdb' +database = 'Driver=SQLite;DATABASE=I2PnetDb' + + +from werkzeug import BaseRequest, BaseResponse, ETagResponseMixin, escape, SharedDataMiddleware +from werkzeug.exceptions import HTTPException +import os +from time import time, gmtime +import calendar +#import time +from random import choice +import pyodbc + + +# +# Not needed? +# +#import sha + + +# db format +# +# table client ipaddress, time of access, file list index +# +# table html index, time of creation, html + + +# +# Init database if it does not exist. +# + +def checkdatabase(): + cnxn = pyodbc.connect(database) + cur = cnxn.cursor() + + try: + cur.execute("select * from client") + except pyodbc.Error: + #cur.execute("create table peer (ip string, time string, index string)") + print ("Creating new table 'client'") + cur.execute("create table client (ip string, whn float)") + cnxn.commit() + try: + cur.execute("select * from entry") + except pyodbc.Error: + #cur.execute("create table peer (ip string, time string, index string)") + print ("Creating new table 'entry'") + cur.execute("create table entry (whn float, wht string)") + cnxn.commit() + cnxn.close() + + + + +# try: +# cur.execute("select * from html") +# except pyodbc.Error: +# cur.execute("create table client (index, time, html)") + + +# cur.execute("insert into foo values(1, 'Me')") +# cnxn.commit() +# cur.execute("select * from foo") +# cnxn.close() + +class Request(BaseRequest): + """Useful subclass of the default request that knows how to build urls.""" + + def __init__(self, environ): + BaseRequest.__init__(self, environ) + + +class Response(BaseResponse, ETagResponseMixin): + """Subclass of base response that has a default mimetype of text/html.""" + default_mimetype = 'text/html' + +def app(environ, start_response): + """The WSGI application that connects all together.""" + req = Request(environ) + remote = req.remote_addr + now = time() + old = now - 3600 + oldest = now - 7200 + t = gmtime(now) + nowtag = calendar.timegm((t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, 0, 0, t.tm_wday, t.tm_yday, t.tm_isdst)) + + cnxn = pyodbc.connect(database) + cur = cnxn.cursor() + # + # Prune database from peers that are over 1 hour old + # + cur.execute("delete from client where whn < ?", old) + cnxn.commit() + # + # Prune database from entries that are over 2 hours old + # + cur.execute("delete from entry where whn < ?", oldest) + cnxn.commit() + + # + # Get peer info + # + cur.execute("select * from client where ip = ?", remote) + info = cur.fetchall() + # page + path = req.path[1:] + + + if path == '': + page = u'NetDB' + + if len(info) == 0: + # tag the ip as new + cur.execute("insert into client values (?, ?)", (remote, now)) + # see if we have a list already, and use that + # generate links + entries = os.listdir(netdbdir) + if len(entries) > 150: + # select some randomly + new = [] + for i in range(100): + while True: + sel = choice(entries) + if not sel.startswith('routerInfo-'): + continue + if sel not in new: + new.append(sel) + cur.execute("insert into entry values (?, ?)", (nowtag, sel)) + break + entries = new + else: + # use old list based on date in database, i.e. sends the same as before. + junk, last = info[0] + t = gmtime(last) + oldtag = calendar.timegm((t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, 0, 0, t.tm_wday, t.tm_yday, t.tm_isdst)) + cur.execute("select * from entry where whn = ?", oldtag) + stuff = cur.fetchall() + entries = [] + for junk,sel in stuff: + entries.append(sel) + + res = '' + for entry in entries: + if not entry.startswith('routerInfo-'): + continue + res += '
  • %s
  • ' % (entry, entry) + resp = Response(page % res, mimetype='text/html') + resp.add_etag() + + elif path == 'robots.txt': + dat = u"User-agent: *\nDisallow: /routerInfo-*.dat$\n" + resp = Response(dat, mimetype='text/plain') + resp.add_etag() + + else: + if len(info) == 0: + # 404 This is to prevent cross seed site scrapes + resp = Response("Hi! Having fun?", status=403, mimetype='text/plain') + else: + # + # zap badness from path + # + chkpath = path.replace("'","").replace("/","") + # check to see if we have this entry in the database at all. + cur.execute("select * from entry where wht = ?", chkpath) + chk = cur.fetchall() + if len(chk) == 0: + resp = Response("Do you not have anything better to do?", status=400, mimetype='text/plain') + else: + try: + # load file + f = open(os.path.join(netdbdir, path), 'rb') + resp = Response(f.read(), mimetype='application/octet-stream') + f.close() + resp.add_etag() + except IOError: + # 404 + resp = Response("Owch! Could not find file!", status=404, mimetype='text/plain') + cnxn.commit() + cnxn.close() + return resp(environ, start_response) + +checkdatabase() + +if __name__ == '__main__': + from werkzeug import run_simple + run_simple('localhost', 5007, app)