started a simple board plugin

This commit is contained in:
Kevin Froman 2018-12-26 00:14:05 -06:00
parent b45bb94375
commit 2289171b0f
10 changed files with 105 additions and 27 deletions

View File

@ -1,6 +0,0 @@
test:
script:
- apt-get update -qy
- apt-get install -y python3-dev python3-pip tor
- pip3 install -r requirements.txt
- make test

View File

@ -1,8 +0,0 @@
language: python
python:
- "3.6.4"
# install dependencies
install:
- sudo apt install tor
- pip install -r requirements.txt
script: make test

2
onionr-daemon-linux Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/sh
nohup ./run-linux start & disown

View File

@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import flask import flask, cgi
from flask import request, Response, abort, send_from_directory from flask import request, Response, abort, send_from_directory
from gevent.pywsgi import WSGIServer from gevent.pywsgi import WSGIServer
import sys, random, threading, hmac, hashlib, base64, time, math, os, json import sys, random, threading, hmac, hashlib, base64, time, math, os, json
@ -221,7 +221,8 @@ class API:
This initilization defines all of the API entry points and handlers for the endpoints and errors This initilization defines all of the API entry points and handlers for the endpoints and errors
This also saves the used host (random localhost IP address) to the data folder in host.txt This also saves the used host (random localhost IP address) to the data folder in host.txt
''' '''
# assert isinstance(onionrInst, onionr.Onionr)
print(type(onionrInst))
# configure logger and stuff # configure logger and stuff
onionr.Onionr.setupConfig('data/', self = self) onionr.Onionr.setupConfig('data/', self = self)
@ -234,6 +235,8 @@ class API:
bindPort = int(config.get('client.client.port', 59496)) bindPort = int(config.get('client.client.port', 59496))
self.bindPort = bindPort self.bindPort = bindPort
self.whitelistEndpoints = ('site', 'www', 'onionrhome', 'board', 'boardContent')
self.clientToken = config.get('client.webpassword') self.clientToken = config.get('client.webpassword')
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
@ -249,6 +252,8 @@ class API:
'''Validate request has set password and is the correct hostname''' '''Validate request has set password and is the correct hostname'''
if request.host != '%s:%s' % (self.host, self.bindPort): if request.host != '%s:%s' % (self.host, self.bindPort):
abort(403) abort(403)
if request.endpoint in self.whitelistEndpoints:
return
try: try:
if not hmac.compare_digest(request.headers['token'], self.clientToken): if not hmac.compare_digest(request.headers['token'], self.clientToken):
abort(403) abort(403)
@ -257,7 +262,8 @@ class API:
@app.after_request @app.after_request
def afterReq(resp): def afterReq(resp):
resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'" #resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'"
resp.headers['Content-Security-Policy'] = "default-src 'none'; script-src 'self'; object-src 'none'; style-src 'self'; img-src 'self'; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'self'"
resp.headers['X-Frame-Options'] = 'deny' resp.headers['X-Frame-Options'] = 'deny'
resp.headers['X-Content-Type-Options'] = "nosniff" resp.headers['X-Content-Type-Options'] = "nosniff"
resp.headers['X-API'] = onionr.API_VERSION resp.headers['X-API'] = onionr.API_VERSION
@ -265,20 +271,54 @@ class API:
resp.headers['Date'] = 'Thu, 1 Jan 1970 00:00:00 GMT' # Clock info is probably useful to attackers. Set to unix epoch. resp.headers['Date'] = 'Thu, 1 Jan 1970 00:00:00 GMT' # Clock info is probably useful to attackers. Set to unix epoch.
return resp return resp
@app.route('/board/', endpoint='board')
def loadBoard():
return send_from_directory('static-data/www/board/', "index.html")
@app.route('/board/<path:path>', endpoint='boardContent')
def boardContent(path):
return send_from_directory('static-data/www/board/', path)
@app.route('/www/<path:path>', endpoint='www')
def wwwPublic(path):
if not config.get("www.private.run", True):
abort(403)
return send_from_directory(config.get('www.private.path', 'static-data/www/private/'), path)
@app.route('/ping') @app.route('/ping')
def ping(): def ping():
return Response("pong!") return Response("pong!")
@app.route('/') @app.route('/', endpoint='onionrhome')
def hello(): def hello():
return Response("hello client") return Response("Welcome to Onionr")
@app.route('/getblocksbytype/<name>')
def getBlocksByType(name):
blocks = self._core.getBlocksByType(name)
return Response(','.join(blocks))
@app.route('/gethtmlsafeblockdata/<name>')
def getData(name):
resp = ''
if self._core._utils.validateHash(name):
try:
resp = cgi.escape(Block(name).bcontent, quote=True)
except TypeError:
pass
else:
abort(404)
return Response(resp)
@app.route('/site/<name>') @app.route('/site/<name>', endpoint='site')
def site(): def site(name):
bHash = block bHash = name
resp = 'Not Found' resp = 'Not Found'
if self._core._utils.validateHash(bHash): if self._core._utils.validateHash(bHash):
resp = Block(bHash).bcontent try:
resp = Block(bHash).bcontent
except TypeError:
pass
try: try:
resp = base64.b64decode(resp) resp = base64.b64decode(resp)
except: except:

View File

@ -268,7 +268,7 @@ class OnionrCrypto:
blockHash = blockHash.decode() # bytes on some versions for some reason blockHash = blockHash.decode() # bytes on some versions for some reason
except AttributeError: except AttributeError:
pass pass
difficulty = onionrproofs.getDifficultyForNewBlock(blockContent, ourBlock=False) difficulty = onionrproofs.getDifficultyForNewBlock(blockContent, ourBlock=False)
if difficulty < int(config.get('general.minimum_block_pow')): if difficulty < int(config.get('general.minimum_block_pow')):

View File

@ -57,6 +57,8 @@ def getDifficultyForNewBlock(data, ourBlock=True):
dataSize = len(data.getRaw().encode('utf-8')) dataSize = len(data.getRaw().encode('utf-8'))
elif isinstance(data, str): elif isinstance(data, str):
dataSize = len(data.encode('utf-8')) dataSize = len(data.encode('utf-8'))
elif isinstance(data, bytes):
dataSize = len(data)
elif isinstance(data, int): elif isinstance(data, int):
dataSize = data dataSize = data
else: else:

View File

@ -2,8 +2,8 @@
"general" : { "general" : {
"dev_mode" : true, "dev_mode" : true,
"display_header" : false, "display_header" : false,
"minimum_block_pow": 4, "minimum_block_pow": 3,
"minimum_send_pow": 4, "minimum_send_pow": 3,
"socket_servers": false, "socket_servers": false,
"security_level": 0, "security_level": 0,
"max_block_age": 2678400, "max_block_age": 2678400,
@ -69,7 +69,7 @@
}, },
"allocations" : { "allocations" : {
"disk" : 2000, "disk" : 100000000,
"net_total" : 1000000000, "net_total" : 1000000000,
"blockCache" : 5000000, "blockCache" : 5000000,
"blockCacheTotal" : 50000000 "blockCacheTotal" : 50000000

View File

@ -0,0 +1,32 @@
webpassword = ''
requested = {}
document.getElementById('feed').innerText = 'none :)'
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest()
xmlHttp.open( "GET", theUrl, false ) // false for synchronous request
xmlHttp.setRequestHeader('token', webpassword)
xmlHttp.send( null )
return xmlHttp.responseText
}
function appendMessages(msg){
document.getElementById('feed').append(msg)
document.getElementById('feed').appendChild(document.createElement('br'))
}
function getBlocks(){
var feedText = httpGet('/getblocksbytype/txt')
var blockList = feedText.split(',')
for (i = 0; i < blockList.length; i++){
bl = httpGet('/gethtmlsafeblockdata/' + blockList[i])
appendMessages(bl)
}
}
document.getElementById('webpassword').oninput = function(){
webpassword = document.getElementById('webpassword').value
}
document.getElementById('refreshFeed').onclick = function(){
getBlocks()
}

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'>
<title>
OnionrBoard
</title>
</head>
<body>
<h1>Onionr Board</h1>
<input id='webpassword' type='password' placeholder="Web password for daemon">
<input type='button' id='refreshFeed' value='Refresh Feed'>
<div id='feed'></div>
<script src='board.js'></script>
</body>
</html>

View File