tons more work on secrets... should be nearly fully functioning, still no API.
This commit is contained in:
parent
ee63abc16c
commit
f6a2e30ce0
5 changed files with 325 additions and 22 deletions
251
brain.py
251
brain.py
|
@ -1,7 +1,7 @@
|
|||
import os, sys
|
||||
from git import *
|
||||
import bottle
|
||||
from bottle import default_app, route, run, request, template, static_file, redirect
|
||||
from bottle import default_app, get, post, route, run, request, template, static_file, redirect
|
||||
from os.path import isdir
|
||||
from string import lower, split
|
||||
from urllib import unquote
|
||||
|
@ -11,6 +11,13 @@ import re
|
|||
import Image
|
||||
from markdown2 import markdown
|
||||
import MySQLdb
|
||||
from contextlib import closing
|
||||
from urllib import urlopen
|
||||
from urlparse import urlparse
|
||||
from contextlib import closing
|
||||
import string
|
||||
import random
|
||||
|
||||
|
||||
try:
|
||||
conn = MySQLdb.connect( host = "localhost",
|
||||
|
@ -29,6 +36,65 @@ conf['ext_bundles'] = ['.pages', '.sparsebundle']
|
|||
conf['ext_render'] = ['.md','.txt','.jpg','.gif','.png']
|
||||
conf['ext_edit'] = ['.md','.txt','.rb','.py','.pl','.sh']
|
||||
|
||||
def get_secrets(url = False):
|
||||
if url:
|
||||
query = 'SELECT base_url,username,password,id FROM `secrets` WHERE base_url LIKE "%' + url + '";'
|
||||
else:
|
||||
query = 'SELECT base_url,username,password,id FROM `secrets`;'
|
||||
|
||||
cursor.execute(query)
|
||||
secrets = cursor.fetchall()
|
||||
|
||||
if not len(secrets) > 0:
|
||||
url = get_domain(url)
|
||||
cursor.execute(query)
|
||||
secrets = cursor.fetchall()
|
||||
|
||||
return secrets
|
||||
|
||||
|
||||
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_generated(domain):
|
||||
get = 'SELECT password FROM secrets_gen WHERE base_url LIKE "%'+get_domain(domain)+'%" LIMIT 1'
|
||||
create = 'INSERT INTO secrets_gen (base_url, password) VALUES ('+get_domain(domain)+','+mkpass()+')'
|
||||
|
||||
cursor.execute(get)
|
||||
gen = cursor.fetchone()
|
||||
|
||||
if not gen:
|
||||
cursor.execute(create)
|
||||
cursor.execute(get)
|
||||
gen = cursor.fetchone()
|
||||
|
||||
return str(gen[0])
|
||||
|
||||
|
||||
def sanitize_path(path):
|
||||
return path.lstrip('./')
|
||||
|
||||
|
@ -673,35 +739,182 @@ def short(short = ''):
|
|||
|
||||
|
||||
# Let's make a place to store my secrets
|
||||
@route('/secrets/<path>')
|
||||
@route('/secrets/')
|
||||
@route('/secrets')
|
||||
def secrets(path = ''):
|
||||
if path and not path == "list":
|
||||
query = 'SELECT username,password FROM `secrets` WHERE base_url LIKE "%' + path + '";'
|
||||
# A big list of secrets, need a special password'
|
||||
@post('/secrets/list')
|
||||
@get('/secrets/list')
|
||||
@get('/secrets/list/')
|
||||
def secret_list(path = ''):
|
||||
|
||||
cursor.execute(query)
|
||||
secrets = cursor.fetchall()
|
||||
body = []
|
||||
|
||||
body = []
|
||||
if request.forms.password == "allyourbasearebelongtous":
|
||||
secrets = get_secrets()
|
||||
|
||||
for s in secrets:
|
||||
body.append(s[0]+' | '+ s[1]+'<br/>')
|
||||
body.append(s[0]+': '+s[1]+' | '+s[2])
|
||||
body.append('<a href="/secrets/trash/'+str(s[3])+'">(x)</a>')
|
||||
body.append('<br/>')
|
||||
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Secrets')
|
||||
else:
|
||||
body.append('<form method="post" action="/secrets/list" />')
|
||||
body.append('<p>Are you sure?</p>')
|
||||
body.append('<table>')
|
||||
body.append('<tr><td>Password:</td>')
|
||||
body.append('<td><input type="password" name="password" /></td></tr>')
|
||||
body.append('<td><td><input type="submit" /></td></tr>')
|
||||
body.append('</table>')
|
||||
body.append('</form>')
|
||||
|
||||
if path == "list":
|
||||
query = 'SELECT base_url,username,password FROM `secrets`;'
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Secrets List')
|
||||
|
||||
cursor.execute(query)
|
||||
secrets = cursor.fetchall()
|
||||
|
||||
body = []
|
||||
# Show the secrets associated with a specific site.
|
||||
@get('/secrets/show/<url>')
|
||||
@get('/secrets/show/')
|
||||
@get('/secrets/show')
|
||||
def secret_lookup(url = False):
|
||||
|
||||
body = []
|
||||
|
||||
if url:
|
||||
secrets = get_secrets(url)
|
||||
for s in secrets:
|
||||
body.append(s[0]+': '+s[1]+' | '+s[2]+'<br/>')
|
||||
body.append(s[0]+': '+s[1]+' | '+s[2])
|
||||
body.append('<a href="/secrets/trash/'+str(s[3])+'">(x)</a>')
|
||||
body.append('<br/>')
|
||||
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Secrets')
|
||||
else:
|
||||
body.append('Must provide a url.')
|
||||
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Secrets for ' + url)
|
||||
|
||||
|
||||
# A form for trashing secrets.
|
||||
@get('/secrets/trash/<key>')
|
||||
@get('/secrets/trash/')
|
||||
@get('/secrets/trash')
|
||||
def secret_trash(key=False):
|
||||
body = []
|
||||
|
||||
body.append('<form method="post" action="/secrets/trash/" >')
|
||||
body.append('<p>Trash a secret</p>')
|
||||
body.append('<table>')
|
||||
body.append('<tr><td><label for="id">Secret id</label></td>')
|
||||
body.append('<td><input name="id" ')
|
||||
if key: body.append('value="'+key+'" ')
|
||||
body.append('/></td></tr>')
|
||||
body.append('<tr><td><input type="submit" /></td></tr>')
|
||||
body.append('</table>')
|
||||
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Trash Secret')
|
||||
|
||||
|
||||
|
||||
# Actually trashing secrets.
|
||||
@post('/secrets/trash')
|
||||
@post('/secrets/trash/')
|
||||
def secret_trash():
|
||||
#query = 'SELECT base_url,username,password,id FROM `secrets` WHERE base_url LIKE "%' + url + '";'
|
||||
#cursor.execute(query)
|
||||
#secrets = cursor.fetchall()
|
||||
original = 'SELECT id FROM `secrets` WHERE id = "' + str(request.forms.id) + '" LIMIT 1'
|
||||
copy = 'INSERT INTO `secrets_trash` SELECT * FROM `secrets` WHERE id = "' + str(request.forms.id) + '"'
|
||||
check = 'SELECT * FROM `secrets_trash` INNER JOIN `secrets` ON (secrets_trash.base_url = secrets.base_url AND secrets_trash.username = secrets.username AND secrets_trash.password = secrets.password)'
|
||||
delete = 'DELETE FROM `secrets` WHERE id = "' + str(request.forms.id) + '" LIMIT 1'
|
||||
|
||||
body = []
|
||||
|
||||
if cursor.execute(original):
|
||||
body.append('<p>Record exists.</p>')
|
||||
cursor.execute(copy)
|
||||
body.append('<p>Record copied.</p>')
|
||||
if cursor.execute(check):
|
||||
body.append('<p>Duplicate records exist.</p>')
|
||||
cursor.execute(delete)
|
||||
body.append('<p>Original record deleted.</p>')
|
||||
if not cursor.execute(original):
|
||||
body.append('<p>Original record does not exist.</p>')
|
||||
body.append('<p>Record ' + str(request.forms.id) + ' trashed.</p>')
|
||||
|
||||
else:
|
||||
body.append('<p>No such record.</p>')
|
||||
|
||||
return template('templates/secret', content = '\n'.join(body), title = 'Secret ' + str(request.forms.id) + ' trashed.')
|
||||
|
||||
|
||||
# Create a new secret.
|
||||
@get('/secrets/create/<url>')
|
||||
@get('/secrets/create/')
|
||||
@get('/secrets/create')
|
||||
def secrets_create(url = False):
|
||||
body = []
|
||||
|
||||
body.append('<h3>Create Secret</h3>')
|
||||
body.append('<form method="POST" action="/secrets/create">')
|
||||
body.append('<table>')
|
||||
body.append('<tr><td><label for="url">URL:</label></td>')
|
||||
body.append('<td><input name="url" ')
|
||||
if url: body.append('value="'+url+'" ')
|
||||
body.append('/></td></tr>')
|
||||
body.append('<tr><td><label for="username">Username:</label></td>')
|
||||
body.append('<td><input name="username" /></td></tr>')
|
||||
body.append('<tr><td><label for="password">Password:</label></td>')
|
||||
body.append('<td><input type="password" name="password" ')
|
||||
if url: body.append('value="'+get_generated(url)+'" ')
|
||||
body.append('/></td></tr>')
|
||||
body.append('<tr><td><input type="submit" /></td></tr>')
|
||||
body.append('</table>')
|
||||
body.append('</form>')
|
||||
|
||||
return template('templates/secret', content='\n'.join(body), title = 'Create Secret')
|
||||
|
||||
|
||||
# Create a new secret
|
||||
@post('/secrets/create')
|
||||
def create_secret():
|
||||
body = []
|
||||
query = 'INSERT INTO secrets (base_url, username, password) VALUES (' +\
|
||||
'"'+request.forms.url+'", '+\
|
||||
'"'+request.forms.username+'", '+\
|
||||
'"'+request.forms.password+'")'
|
||||
|
||||
print query
|
||||
|
||||
if cursor.execute(query):
|
||||
body.append('<p>Secret created.</p>')
|
||||
body.append('<p>View secrets for <a href="/secrets/show/'+\
|
||||
request.forms.url+'">'+request.forms.url+'</a>.</p>')
|
||||
else:
|
||||
body.append('Secret could not be created.')
|
||||
|
||||
return template('templates/secret', content='\n'.join(body), title = 'Create Secret')
|
||||
|
||||
|
||||
|
||||
@get('/secrets/overlay/<url>')
|
||||
def secret_overlay(url):
|
||||
body = []
|
||||
body.append('<p>Secrets for: '+url+'</p>')
|
||||
|
||||
secrets = get_secrets(url)
|
||||
for s in secrets:
|
||||
body.append(s[0] + ': ' + s[1] + ' | ' + s[2] + '<br/>')
|
||||
|
||||
gen = get_generated(url)
|
||||
|
||||
body.append('<p>Generated: ' + gen + '</p>')
|
||||
|
||||
body.append('<form method="POST" action="/secrets/create" target="_blank">')
|
||||
body.append('<table>')
|
||||
body.append('<tr><td>URL:</td><td><input name="base_url" value="'+url+'" /></td></tr>')
|
||||
body.append('<tr><td>U:</td><td><input name="username" /></td></tr>')
|
||||
body.append('<tr><td>P:</td><td><input name="password" type="password" value="'+gen+'" /></td></tr>')
|
||||
body.append('<tr><td><input type="submit" /></td></tr>')
|
||||
body.append('</table>')
|
||||
body.append('</form>')
|
||||
|
||||
return template('templates/overlay', content='\n'.join(body), title = url + ' overlay')
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
body {
|
||||
body, table {
|
||||
background-color: #CCC;
|
||||
color: #3c3c3c;
|
||||
font-family: Helvetica;
|
||||
|
|
77
static/overlay.js
Normal file
77
static/overlay.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
(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/secrets/overlay/'+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);
|
||||
|
||||
})();
|
15
templates/overlay.tpl
Normal file
15
templates/overlay.tpl
Normal file
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>{{title or 'myStuff'}}</title>
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/brain.css" />
|
||||
<style type="text/css">
|
||||
body, table {
|
||||
background: #FFF !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{!content}}
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,3 @@
|
|||
{{!content}}
|
||||
|
||||
<p>Back to <a href="/repo">Repo</a></p>
|
||||
|
||||
%rebase templates/layout title=title
|
||||
|
|
Loading…
Reference in a new issue