2017-12-26 07:25:29 +00:00
|
|
|
'''
|
2019-06-12 00:05:15 +00:00
|
|
|
Onionr - Private P2P Communication
|
2018-01-14 08:48:23 +00:00
|
|
|
|
|
|
|
This file handles all incoming http requests to the client, using Flask
|
|
|
|
'''
|
|
|
|
'''
|
2017-12-26 07:25:29 +00:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
'''
|
2019-07-12 07:07:30 +00:00
|
|
|
import base64, os
|
2019-06-15 18:56:57 +00:00
|
|
|
import flask
|
2019-07-12 07:07:30 +00:00
|
|
|
from gevent.pywsgi import WSGIServer
|
|
|
|
import logger
|
|
|
|
from onionrutils import epoch
|
2019-03-02 06:22:59 +00:00
|
|
|
import httpapi
|
2019-07-12 07:07:30 +00:00
|
|
|
from . import register_private_blueprints
|
|
|
|
class PrivateAPI:
|
2019-01-08 05:51:39 +00:00
|
|
|
'''
|
|
|
|
Client HTTP api
|
|
|
|
'''
|
2018-02-04 03:44:29 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
callbacks = {'public' : {}, 'private' : {}}
|
2018-12-09 17:29:39 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
def __init__(self, onionrInst, debug, API_VERSION):
|
|
|
|
'''
|
|
|
|
Initialize the api server, preping variables for later use
|
2017-12-27 01:13:19 +00:00
|
|
|
|
2019-04-23 02:02:09 +00:00
|
|
|
This initialization defines all of the API entry points and handlers for the endpoints and errors
|
2019-01-08 05:51:39 +00:00
|
|
|
This also saves the used host (random localhost IP address) to the data folder in host.txt
|
2018-02-04 03:44:29 +00:00
|
|
|
'''
|
2019-07-12 07:07:30 +00:00
|
|
|
config = onionrInst.config
|
|
|
|
self.config = config
|
2019-01-08 05:51:39 +00:00
|
|
|
self.debug = debug
|
2019-01-20 22:54:04 +00:00
|
|
|
self._core = onionrInst.onionrCore
|
2019-06-25 23:07:35 +00:00
|
|
|
self.startTime = epoch.get_epoch()
|
2019-07-12 07:07:30 +00:00
|
|
|
self._crypto = self._core._crypto
|
2019-01-08 05:51:39 +00:00
|
|
|
app = flask.Flask(__name__)
|
|
|
|
bindPort = int(config.get('client.client.port', 59496))
|
|
|
|
self.bindPort = bindPort
|
2018-05-19 21:32:21 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
self.clientToken = config.get('client.webpassword')
|
|
|
|
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
|
2018-05-19 21:32:21 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
self.publicAPI = None # gets set when the thread calls our setter... bad hack but kinda necessary with flask
|
|
|
|
#threading.Thread(target=PublicAPI, args=(self,)).start()
|
2019-07-12 07:07:30 +00:00
|
|
|
self.host = httpapi.apiutils.setbindip.set_bind_IP(self._core.privateApiHostFile, self._core)
|
2019-01-08 05:51:39 +00:00
|
|
|
logger.info('Running api on %s:%s' % (self.host, self.bindPort))
|
|
|
|
self.httpServer = ''
|
2019-01-07 05:50:20 +00:00
|
|
|
|
|
|
|
self.queueResponse = {}
|
2019-01-08 05:51:39 +00:00
|
|
|
onionrInst.setClientAPIInst(self)
|
2019-02-10 02:21:36 +00:00
|
|
|
|
2019-07-12 07:07:30 +00:00
|
|
|
httpapi.load_plugin_blueprints(self, app)
|
|
|
|
self.get_block_data = httpapi.apiutils.GetBlockData(self)
|
|
|
|
|
|
|
|
self.httpServer = WSGIServer((self.host, bindPort), app, log=None, handler_class=httpapi.fdsafehandler.FDSafeHandler)
|
2019-01-08 05:51:39 +00:00
|
|
|
self.httpServer.serve_forever()
|
2018-07-30 00:37:12 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
def setPublicAPIInstance(self, inst):
|
|
|
|
self.publicAPI = inst
|
2018-07-30 00:37:12 +00:00
|
|
|
|
2019-01-08 05:51:39 +00:00
|
|
|
def validateToken(self, token):
|
|
|
|
'''
|
2019-02-12 05:30:56 +00:00
|
|
|
Validate that the client token matches the given token. Used to prevent CSRF and data exfiltration
|
2019-01-08 05:51:39 +00:00
|
|
|
'''
|
|
|
|
if len(self.clientToken) == 0:
|
|
|
|
logger.error("client password needs to be set")
|
|
|
|
return False
|
|
|
|
try:
|
|
|
|
if not hmac.compare_digest(self.clientToken, token):
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
except TypeError:
|
|
|
|
return False
|
2019-01-13 22:20:10 +00:00
|
|
|
|
|
|
|
def getUptime(self):
|
2019-01-28 22:49:04 +00:00
|
|
|
while True:
|
|
|
|
try:
|
2019-06-25 23:07:35 +00:00
|
|
|
return epoch.get_epoch() - self.startTime
|
2019-04-12 17:14:16 +00:00
|
|
|
except (AttributeError, NameError):
|
2019-01-28 22:49:04 +00:00
|
|
|
# Don't error on race condition with startup
|
2019-02-01 06:38:12 +00:00
|
|
|
pass
|
2019-07-01 20:38:55 +00:00
|
|
|
|
2019-02-04 23:48:21 +00:00
|
|
|
def getBlockData(self, bHash, decrypt=False, raw=False, headerOnly=False):
|
2019-07-12 07:07:30 +00:00
|
|
|
return self.get_block_data.get_block_data(bHash, decrypt=decrypt, raw=raw, headerOnly=headerOnly)
|