prepare public api
This commit is contained in:
parent
507b6fed3e
commit
dd0e22a979
18 changed files with 237 additions and 94 deletions
|
|
@ -113,6 +113,7 @@ def find(data):
|
|||
response['size'] = sum(size)
|
||||
return response
|
||||
actions.register(find)
|
||||
actions.register(find, version='public')
|
||||
|
||||
|
||||
def get(data):
|
||||
|
|
@ -128,6 +129,7 @@ def get(data):
|
|||
response = item.json(data['keys'] if 'keys' in data else None)
|
||||
return response
|
||||
actions.register(get)
|
||||
actions.register(get, version='public')
|
||||
|
||||
|
||||
def edit(data):
|
||||
|
|
|
|||
|
|
@ -71,8 +71,9 @@ def defaultcontext():
|
|||
class ApiHandler(tornado.web.RequestHandler):
|
||||
executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)
|
||||
|
||||
def initialize(self, context=None):
|
||||
def initialize(self, context=None, public=False):
|
||||
self._context = context
|
||||
self._public = public
|
||||
|
||||
def get(self):
|
||||
self.write('use POST')
|
||||
|
|
@ -81,7 +82,7 @@ class ApiHandler(tornado.web.RequestHandler):
|
|||
def api_task(self, request):
|
||||
import settings
|
||||
context = self._context
|
||||
if context == None:
|
||||
if context is None:
|
||||
context = defaultcontext
|
||||
action = request.arguments.get('action', [None])[0].decode('utf-8')
|
||||
data = request.arguments.get('data', [b'{}'])[0]
|
||||
|
|
@ -96,7 +97,10 @@ class ApiHandler(tornado.web.RequestHandler):
|
|||
else:
|
||||
if settings.DEBUG_API:
|
||||
logger.debug('API %s %s', action, data)
|
||||
f = actions.get(action)
|
||||
if self._public:
|
||||
f = actions.versions['public'].get(action)
|
||||
else:
|
||||
f = actions.get(action)
|
||||
if f:
|
||||
with context():
|
||||
try:
|
||||
|
|
@ -126,50 +130,60 @@ class ApiHandler(tornado.web.RequestHandler):
|
|||
class ApiActions(dict):
|
||||
properties = {}
|
||||
versions = {}
|
||||
def __init__(self):
|
||||
|
||||
def api(data):
|
||||
'''
|
||||
returns list of all known api actions
|
||||
takes {
|
||||
docs: bool
|
||||
}
|
||||
if docs is true, action properties contain docstrings
|
||||
returns {
|
||||
actions: {
|
||||
'api': {
|
||||
cache: true,
|
||||
doc: 'recursion'
|
||||
},
|
||||
'hello': {
|
||||
cache: true,
|
||||
..
|
||||
}
|
||||
...
|
||||
def _api(self, data, version=None):
|
||||
'''
|
||||
returns list of all known api actions
|
||||
takes {
|
||||
docs: bool
|
||||
}
|
||||
if docs is true, action properties contain docstrings
|
||||
returns {
|
||||
actions: {
|
||||
'api': {
|
||||
cache: true,
|
||||
doc: 'recursion'
|
||||
},
|
||||
'hello': {
|
||||
cache: true,
|
||||
..
|
||||
}
|
||||
...
|
||||
}
|
||||
'''
|
||||
data = data or {}
|
||||
docs = data.get('docs', False)
|
||||
code = data.get('code', False)
|
||||
}
|
||||
'''
|
||||
data = data or {}
|
||||
docs = data.get('docs', False)
|
||||
code = data.get('code', False)
|
||||
if version:
|
||||
_actions = list(self.versions[version].keys())
|
||||
else:
|
||||
_actions = list(self.keys())
|
||||
_actions.sort()
|
||||
actions = {}
|
||||
for a in _actions:
|
||||
actions[a] = self.properties[a]
|
||||
if docs:
|
||||
actions[a]['doc'] = self.doc(a)
|
||||
if code:
|
||||
actions[a]['code'] = self.code(a)
|
||||
return {'actions': actions}
|
||||
self.register(api)
|
||||
_actions.sort()
|
||||
actions = {}
|
||||
for a in _actions:
|
||||
actions[a] = self.properties[a]
|
||||
if docs:
|
||||
actions[a]['doc'] = self.doc(a, version)
|
||||
if code:
|
||||
actions[a]['code'] = self.code(a, version)
|
||||
return {'actions': actions}
|
||||
|
||||
def doc(self, name):
|
||||
f = self[name]
|
||||
def __init__(self):
|
||||
self.register(self._api, 'api')
|
||||
|
||||
def doc(self, name, version=None):
|
||||
if version:
|
||||
f = self.versions[version][name]
|
||||
else:
|
||||
f = self[name]
|
||||
return trim(f.__doc__)
|
||||
|
||||
def code(self, name, version=None):
|
||||
f = self[name]
|
||||
if version:
|
||||
f = self.versions[version][name]
|
||||
else:
|
||||
f = self[name]
|
||||
if name != 'api' and hasattr(f, 'func_closure') and f.__closure__:
|
||||
fc = [c for c in f.__closure__ if hasattr(c.cell_contents, '__call__')]
|
||||
f = fc[len(fc)-1].cell_contents
|
||||
|
|
@ -181,8 +195,9 @@ class ApiActions(dict):
|
|||
if not action:
|
||||
action = method.__name__
|
||||
if version:
|
||||
if not version in self.versions:
|
||||
if version not in self.versions:
|
||||
self.versions[version] = {}
|
||||
self.register(lambda data: self._api(data, version), action='api', version=version)
|
||||
self.versions[version][action] = method
|
||||
else:
|
||||
self[action] = method
|
||||
|
|
@ -192,4 +207,5 @@ class ApiActions(dict):
|
|||
if action in self:
|
||||
del self[action]
|
||||
|
||||
|
||||
actions = ApiActions()
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ def run():
|
|||
else:
|
||||
debug = False
|
||||
|
||||
log_format='%(asctime)s:%(levelname)s:%(name)s:%(message)s'
|
||||
log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s'
|
||||
if debug:
|
||||
logging.basicConfig(level=logging.DEBUG, format=log_format)
|
||||
else:
|
||||
|
|
@ -109,7 +109,7 @@ def run():
|
|||
'gzip': True
|
||||
}
|
||||
|
||||
handlers = [
|
||||
common_handlers = [
|
||||
(r'/(favicon.ico)', StaticFileHandler, {'path': settings.static_path}),
|
||||
(r'/static/oxjs/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'oxjs')}),
|
||||
(r'/static/cbr.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'cbr.js')}),
|
||||
|
|
@ -126,17 +126,33 @@ def run():
|
|||
'attachment': True
|
||||
}),
|
||||
(r'/(.*)/(cover|preview)(\d*).jpg', IconHandler),
|
||||
]
|
||||
handlers = common_handlers + [
|
||||
(r'/api/upload/', UploadHandler, dict(context=db.session)),
|
||||
(r'/api/', oxtornado.ApiHandler, dict(context=db.session)),
|
||||
(r'/ws', websocket.Handler),
|
||||
(r"(.*)", MainHandler),
|
||||
]
|
||||
public_handlers = common_handlers + [
|
||||
(r'/api/', oxtornado.ApiHandler, dict(context=db.session, public=True)),
|
||||
(r'/ws', websocket.Handler, dict(public=True)),
|
||||
(r"(.*)", MainHandler),
|
||||
]
|
||||
|
||||
setup.create_db()
|
||||
http_server = Application(handlers, **options)
|
||||
max_buffer_size = 2*1024*1024*1024
|
||||
http_server.listen(settings.server['port'], settings.server['address'], max_buffer_size=max_buffer_size)
|
||||
|
||||
# public server
|
||||
'''
|
||||
public_port = settings.server.get('public_port')
|
||||
public_address = settings.server['public_address']
|
||||
if public_port:
|
||||
public_server = Application(public_handlers, **options)
|
||||
public_server.listen(public_port, public_address)
|
||||
'''
|
||||
|
||||
if PID:
|
||||
with open(PID, 'w') as pid:
|
||||
pid.write('%s' % os.getpid())
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ server_defaults = {
|
|||
'port': 9842,
|
||||
'address': '127.0.0.1',
|
||||
'node_port': 9851,
|
||||
'public_address': '127.0.0.1',
|
||||
'public_port': 9852,
|
||||
'node_address': '',
|
||||
'extract_text': True,
|
||||
'localnode_discovery': True,
|
||||
|
|
|
|||
|
|
@ -200,6 +200,8 @@ class Tor(object):
|
|||
key_content = RSA.importKey(private_key).exportKey().decode()
|
||||
key_content = ''.join(key_content.strip().split('\n')[1:-1])
|
||||
ports = {9851: settings.server['node_port']}
|
||||
if settings.preferences.get('enableReadOnlyService'):
|
||||
ports[80] = settings.server['public_port']
|
||||
controller.remove_ephemeral_hidden_service(settings.USER_ID)
|
||||
response = controller.create_ephemeral_hidden_service(ports,
|
||||
key_type='RSA1024', key_content=key_content,
|
||||
|
|
@ -207,6 +209,8 @@ class Tor(object):
|
|||
if response.is_ok():
|
||||
logger.debug('published node as https://%s.onion:%s',
|
||||
settings.USER_ID, settings.server_defaults['node_port'])
|
||||
if settings.preferences.get('enableReadOnlyService'):
|
||||
logger.debug('published readonly version as hidden servers: http://%s.onion', settings.USER_ID)
|
||||
else:
|
||||
logger.debug('failed to publish node to tor')
|
||||
else:
|
||||
|
|
@ -217,6 +221,9 @@ class Tor(object):
|
|||
target_port=settings.server['node_port']
|
||||
)
|
||||
logger.debug('published node as https://%s:%s', result.hostname, settings.server_defaults['node_port'])
|
||||
if settings.preferences.get('enableReadOnlyService'):
|
||||
logger.error('can not publish read-only version, please update TOR')
|
||||
|
||||
|
||||
def depublish(self):
|
||||
if not self.connected:
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ def verify(release):
|
|||
value = '\n'.join(value)
|
||||
value = value.encode()
|
||||
for digest in ('sha512', 'sha256', 'sha1'):
|
||||
if 'signature_%s'%digest in release:
|
||||
tls_sig = base64.b64decode(release['signature_%s'%digest].encode())
|
||||
if 'signature_%s' % digest in release:
|
||||
tls_sig = base64.b64decode(release['signature_%s' % digest].encode())
|
||||
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, settings.OML_UPDATE_CERT)
|
||||
try:
|
||||
OpenSSL.crypto.verify(cert, tls_sig, value, digest)
|
||||
|
|
@ -301,6 +301,7 @@ def getVersion(data):
|
|||
response['update'] = current < new
|
||||
return response
|
||||
actions.register(getVersion, cache=False)
|
||||
actions.register(getVersion, cache=False, version='public')
|
||||
|
||||
def restart(data):
|
||||
'''
|
||||
|
|
|
|||
|
|
@ -55,6 +55,21 @@ def init(data):
|
|||
return response
|
||||
actions.register(init)
|
||||
|
||||
def public_init(data):
|
||||
response = init(data)
|
||||
name = response['user']['preferences']['username']
|
||||
response['user'] = response['config']['user']
|
||||
response['user']['preferences']['username'] = name
|
||||
response['user']['ui']['page'] = ''
|
||||
response['user']['ui']['showFolder'] = {'': True}
|
||||
response['readOnly'] = True
|
||||
for page in response['config']['pages']:
|
||||
if page['id'] == 'preferences':
|
||||
#page['parts'] = [p for p in page['parts'] if p['id'] in ('appearance', 'extensions')]
|
||||
page['parts'] = [p for p in page['parts'] if p['id'] in ('appearance',)]
|
||||
return response
|
||||
actions.register(public_init, action='init', version='public')
|
||||
|
||||
|
||||
def setPreferences(data):
|
||||
'''
|
||||
|
|
@ -149,6 +164,12 @@ def getUsers(data):
|
|||
}
|
||||
actions.register(getUsers)
|
||||
|
||||
def getUsersPublic(data):
|
||||
return {
|
||||
'users': []
|
||||
}
|
||||
actions.register(getUsersPublic, 'getUsers', version='public')
|
||||
|
||||
|
||||
def getLists(data):
|
||||
'''
|
||||
|
|
@ -172,6 +193,29 @@ def getLists(data):
|
|||
}
|
||||
actions.register(getLists)
|
||||
|
||||
def getListsPublic(data):
|
||||
'''
|
||||
returns {
|
||||
lists: []
|
||||
}
|
||||
'''
|
||||
from item.models import Item
|
||||
from sqlalchemy.sql import operators
|
||||
user = state.user()
|
||||
lists = []
|
||||
lists.append({
|
||||
'id': '',
|
||||
'items': user.items.count(),
|
||||
'name': 'Libraries',
|
||||
'type': 'libraries',
|
||||
'user': None,
|
||||
})
|
||||
lists += user.lists_json()
|
||||
return {
|
||||
'lists': lists
|
||||
}
|
||||
actions.register(getListsPublic, 'getLists', version='public')
|
||||
|
||||
def validate_query(query):
|
||||
validate_conditions(query['conditions'])
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
class Handler(WebSocketHandler):
|
||||
|
||||
def initialize(self, public=False):
|
||||
self._public = public
|
||||
|
||||
def check_origin(self, origin):
|
||||
# allow access to websocket from site, installer and loader (local file)
|
||||
return self.request.host in origin or \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue