298 lines
8.6 KiB
Python
Executable file
298 lines
8.6 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import string
|
|
import random
|
|
import web
|
|
from web import form
|
|
from urllib import urlopen
|
|
from urlparse import urlparse
|
|
from contextlib import closing
|
|
import time
|
|
import MySQLdb
|
|
|
|
conn = MySQLdb.connect(host = "localhost",
|
|
user = "brain",
|
|
passwd = "horsebatteries",
|
|
db = "brain")
|
|
|
|
|
|
db = web.database(dbn='mysql', user='mysecrets', pw='horsebatteries',
|
|
db='mysecrets')
|
|
|
|
urls = (
|
|
'/secret/api/(.*)', 'api',
|
|
'/secret/(.*)', 'index'
|
|
)
|
|
|
|
app = web.application(urls, globals())
|
|
|
|
render = web.template.render('templates/')
|
|
|
|
create = form.Form(
|
|
form.Textbox('base_url', description="domain"),
|
|
form.Textbox('username'),
|
|
form.Password('password'),
|
|
)
|
|
|
|
def trash(id):
|
|
if db.select('passwords', where='id = "'+id+'"'):
|
|
|
|
if not db.select('trash', where='id = "'+id+'"'):
|
|
db.query('INSERT INTO trash SELECT * FROM passwords WHERE id = "'+id+'"')
|
|
|
|
orig = db.select('passwords', where='id = "'+id+'"')[0]
|
|
new = db.select('trash', where='id = "'+id+'"')[0]
|
|
|
|
if orig == new:
|
|
db.delete('passwords', where='id = "'+id+'"')
|
|
return True;
|
|
|
|
return False;
|
|
|
|
def get_domain(base_url):
|
|
with closing(urlopen('https://mxr.mozilla.org/mozilla/source/netwerk/dns/src/effective_tld_names.dat?raw=1')) as tldFile:
|
|
tlds = [line.strip() for line in tldFile if line[0] not in "/\n"]
|
|
|
|
urlElements = base_url.split('.')
|
|
|
|
for i in range(-len(urlElements),0):
|
|
lastIElements = urlElements[i:]
|
|
|
|
candidate = ".".join(lastIElements)
|
|
wildcardCandidate = ".".join(["*"]+lastIElements[1:])
|
|
exceptionCandidate = "!"+candidate
|
|
|
|
if (exceptionCandidate in tlds):
|
|
return ".".join(urlElements[i:])
|
|
if (candidate in tlds or wildcardCandidate in tlds):
|
|
return ".".join(urlElements[i-1:])
|
|
|
|
return base_url
|
|
|
|
def mkpass(size=10):
|
|
validChars = string.ascii_letters + string.digits
|
|
validChars = validChars.strip("oO01l")
|
|
|
|
return string.join([random.choice(validChars) for x in range(size)],"")
|
|
|
|
def get_pair_from_url(domain):
|
|
a = db.select('passwords', where='base_url LIKE "%'+domain+'%"', order='id DESC')
|
|
|
|
if not len(a) > 0:
|
|
a = db.select('passwords', where='base_url LIKE "%'+get_domain(domain)+'%"',
|
|
order='id DESC')
|
|
|
|
return a
|
|
|
|
def get_generated_from_url(domain):
|
|
gen = db.select('generated', where='base_url LIKE "%'+get_domain(domain)+'%"',
|
|
order='id DESC')
|
|
|
|
while not len(gen) > 0:
|
|
db.insert('generated', base_url = domain, password = mkpass())
|
|
gen = db.select('generated', where='base_url LIKE "%'+domain+'%"')
|
|
|
|
return gen[0].password
|
|
|
|
|
|
class index:
|
|
def GET(self, method):
|
|
|
|
if method == 'del':
|
|
i = web.input()
|
|
|
|
result = trash(i.id)
|
|
|
|
if result:
|
|
body = "id: " + i.id + " deleted."
|
|
|
|
if not result:
|
|
body = "id: " + i.id + " not deleted."
|
|
|
|
return render.page('Deleted ' + i.id, body)
|
|
|
|
|
|
if method == 'new':
|
|
|
|
start = time.time()
|
|
|
|
i = web.input()
|
|
|
|
f = create()
|
|
|
|
body = []
|
|
|
|
domain = i.base_url
|
|
|
|
body.append('<h1>'+domain+'</h1>')
|
|
|
|
selected = get_pair_from_url(i.base_url)
|
|
generated = get_generated_from_url(i.base_url)
|
|
|
|
if selected:
|
|
body.append('<h2>Existing:</h2>\n<ul>')
|
|
for pair in selected:
|
|
body.append('<li class="pair">'+pair.username+' '+pair.password+
|
|
' <span style="vertical-align:middle;display:inline-block;"><a class="del" \
|
|
href="/secret/del?id='+str(pair.id)+'">(x)</a></span></li>')
|
|
body.append('</ul>')
|
|
|
|
body.append('<h2>Suggested:</h2>\n<p>' + generated + '</p>')
|
|
body.append('<h2>Create:</h2>')
|
|
|
|
body.append('<form class="form" method="get" action="/secret/create"><table>')
|
|
body.append('<tr><td><label for="base_url">Domain</label></td>')
|
|
body.append('<td><input id="base_url" type="text" name="base_url" \
|
|
value="'+domain+'" /></td></tr>')
|
|
body.append('<tr><td><label for="username">Username</label></td>')
|
|
body.append('<td><input id="username" type="text" name="username" /></td></tr>')
|
|
body.append('<tr><td><label for="password">Password</label></td>')
|
|
body.append('<td><input id="password" type="text" name="password" \
|
|
value="'+generated+'"/></td></tr>')
|
|
body.append('<tr><td style="text-align:center;"><input type="submit" \
|
|
name="submit" id="submit" value="Store Secret" /></td></tr>')
|
|
body.append('</table></form>')
|
|
|
|
body.append('<p>Rendered in '+str(round(time.time()-start,3))+' seconds</p>')
|
|
|
|
return render.page(domain,'\n'.join(body))
|
|
|
|
|
|
if method == 'create':
|
|
i = web.input()
|
|
|
|
exists = db.select('passwords', where='username="'+i.username+'" and password="' +\
|
|
i.password+'" and base_url="'+i.base_url+'"')
|
|
|
|
if not exists:
|
|
n = db.insert('passwords', username=i.username, password=i.password, \
|
|
base_url=i.base_url)
|
|
|
|
raise web.seeother('/secret/new?base_url='+i.base_url)
|
|
|
|
if method == 'js-overlay':
|
|
return '''\
|
|
(function() {
|
|
function cleanHouse() {
|
|
elements = document.querySelectorAll('.myS');
|
|
for (i=0; i<elements.length; i++) {
|
|
elements[i].parentNode.removeChild(elements[i]);
|
|
}
|
|
}
|
|
|
|
cleanHouse();
|
|
|
|
s=document.createElement('style');
|
|
s.id='myS-style';
|
|
s.type='text/css';
|
|
s.className+='myS';
|
|
s.innerHTML='\
|
|
.myS{\
|
|
font-family:Georgia;\
|
|
color:#3C3C3C;\
|
|
text-align:center;\
|
|
text-size:14px;\
|
|
}\
|
|
.myS iframe {\
|
|
border: none;\
|
|
}\
|
|
.myS p {\
|
|
color:#3C3C3C;\
|
|
padding:10px;\
|
|
}\
|
|
.myS a {\
|
|
text-decoration:none;\
|
|
color:#3C3C3C;\
|
|
}\
|
|
.myS a:hover{\
|
|
text-decoration:underline;\
|
|
}\
|
|
.myS a.close:hover {\
|
|
border:1px solid #F00;\
|
|
text-decoration:none;\
|
|
color:#F00;\
|
|
}\
|
|
';
|
|
document.body.appendChild(s);
|
|
|
|
o=document.createElement('div');
|
|
o.id='myS-overlay';
|
|
o.className+='myS';
|
|
o.style.position='fixed';
|
|
o.style.left=o.style.right=o.style.top=o.style.bottom='0%';
|
|
o.style.zIndex='1337';
|
|
o.style.backgroundColor='rgba(0,0,0,0.7)';
|
|
document.body.appendChild(o);
|
|
|
|
i=document.createElement('div');
|
|
i.id='myS-inner';
|
|
i.className+='myS';
|
|
i.style.position='relative';
|
|
i.style.margin='0em auto';
|
|
i.style.marginTop='20px';
|
|
i.style.backgroundColor='rgba(255,255,255,1)';
|
|
o.appendChild(i);
|
|
|
|
f=document.createElement('iframe');
|
|
f.id='myS-iframe';
|
|
f.className+='myS';
|
|
f.width=320;
|
|
f.height=320;
|
|
f.style.overflow='auto';
|
|
f.src='https://amdavidson.net/secret/new?base_url='+document.domain;
|
|
i.appendChild(f);
|
|
|
|
e=document.createElement('p');
|
|
e.className+='myS';
|
|
e.onclick=function(){cleanHouse();};
|
|
e.innerHTML='<a style="font-size:10pt;" class="myS close">Close</a>';
|
|
i.appendChild(e);
|
|
|
|
})();'''
|
|
|
|
if method == 'js':
|
|
return '''\
|
|
(function() {
|
|
window.open('https://amdavidson.net/secret/new?base_url='+document.domain,'mySecret','status=no,directories=no,location=no,resizable=no,menubar=no,width=320,height=480,toolbar=no');
|
|
})();
|
|
'''
|
|
|
|
else:
|
|
return render.page('mySecrets', '<p>These are mySecrets. There is nothing for you here.</p>')
|
|
|
|
class api:
|
|
def GET(self, method):
|
|
if method == "list":
|
|
tmp = ''
|
|
for pair in db.select('passwords'):
|
|
tmp += pair['base_url']+','+pair['username']+','+pair['password']+'\n'
|
|
|
|
return tmp
|
|
|
|
if method == "get":
|
|
i = web.input()
|
|
base_url = i.base_url
|
|
pairs = db.select('passwords', where='`base_url`="'+base_url+'"')
|
|
|
|
tmp = ''
|
|
for pair in pairs:
|
|
tmp += pair.username+','+pair.password+'\n'
|
|
|
|
return tmp
|
|
|
|
else:
|
|
return 'mySecrets API ' + method
|
|
|
|
def POST(self, method):
|
|
i = web.input()
|
|
n = db.insert('passwords', username=i.username, password=i.password, \
|
|
base_url=i.base_url)
|
|
|
|
body = '<h1>'+i.base_url+'</h1><p>'+i.username+', '+i.password+'</p>'
|
|
|
|
return render.page('Created', body)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
web.wsgi.runwsgi = lambda func, addr=None: web.wsgi.runfcgi(func, addr)
|
|
app.run()
|