mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Cross-domain bugfix + Simplify and document
This commit is contained in:
parent
588ee4b13f
commit
5c6e68dcfb
1 changed files with 59 additions and 48 deletions
107
yunohost.tac
107
yunohost.tac
|
@ -5,16 +5,11 @@ import gettext
|
||||||
import ldap
|
import ldap
|
||||||
import yaml
|
import yaml
|
||||||
import json
|
import json
|
||||||
from twisted.python import log
|
from twisted.python.log import ILogObserver, FileLogObserver, startLogging
|
||||||
|
from twisted.python.logfile import DailyLogFile
|
||||||
from twisted.web.server import Site
|
from twisted.web.server import Site
|
||||||
from twisted.web.resource import IResource
|
from twisted.internet import reactor
|
||||||
from twisted.web.guard import HTTPAuthSessionWrapper, BasicCredentialFactory
|
from twisted.application import internet,service
|
||||||
from twisted.internet import reactor, defer
|
|
||||||
from twisted.cred.portal import IRealm, Portal
|
|
||||||
from twisted.cred.checkers import ICredentialsChecker
|
|
||||||
from twisted.cred.credentials import IUsernamePassword
|
|
||||||
from twisted.cred.error import UnauthorizedLogin
|
|
||||||
from zope.interface import implements
|
|
||||||
from txrestapi.resource import APIResource
|
from txrestapi.resource import APIResource
|
||||||
from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, validate, win, parse_dict
|
from yunohost import YunoHostError, YunoHostLDAP, str_to_func, colorize, pretty_print_dict, display_error, validate, win, parse_dict
|
||||||
|
|
||||||
|
@ -23,39 +18,33 @@ if not __debug__:
|
||||||
|
|
||||||
gettext.install('YunoHost')
|
gettext.install('YunoHost')
|
||||||
|
|
||||||
class LDAPHTTPAuth():
|
|
||||||
implements (ICredentialsChecker)
|
|
||||||
|
|
||||||
credentialInterfaces = IUsernamePassword,
|
|
||||||
|
|
||||||
def requestAvatarId(self, credentials):
|
|
||||||
try:
|
|
||||||
if credentials.username != "admin":
|
|
||||||
raise YunoHostError(22, _("Invalid username") + ': ' + credentials.username)
|
|
||||||
YunoHostLDAP(password=credentials.password)
|
|
||||||
return credentials.username
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return defer.fail(UnauthorizedLogin())
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleRealm(object):
|
|
||||||
implements(IRealm)
|
|
||||||
|
|
||||||
_api = None
|
|
||||||
|
|
||||||
def __init__(self, api):
|
|
||||||
self._api = api
|
|
||||||
|
|
||||||
def requestAvatar(self, avatarId, mind, *interfaces):
|
|
||||||
if IResource in interfaces:
|
|
||||||
return IResource, self._api, lambda: None
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
action_dict = {}
|
action_dict = {}
|
||||||
|
api = APIResource()
|
||||||
|
|
||||||
def http_exec(request):
|
def http_exec(request):
|
||||||
global win
|
global win
|
||||||
|
|
||||||
|
request.setHeader('Access-Control-Allow-Origin', '*') # Allow cross-domain requests
|
||||||
|
request.setHeader('Content-Type', 'application/json') # Return JSON anyway
|
||||||
|
|
||||||
|
# Return OK to 'OPTIONS' xhr requests
|
||||||
|
if request.method == 'OPTIONS':
|
||||||
|
request.setResponseCode(200, 'OK')
|
||||||
|
request.setHeader('Access-Control-Allow-Headers', 'Authorization')
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# Simple HTTP auth
|
||||||
|
else:
|
||||||
|
authorized = request.getUser() == 'admin'
|
||||||
|
try: YunoHostLDAP(password=request.getPassword())
|
||||||
|
except YunoHostError: authorized = False
|
||||||
|
|
||||||
|
if not authorized:
|
||||||
|
request.setResponseCode(401, 'Unauthorized')
|
||||||
|
request.setHeader('Access-Control-Allow-Origin', '*')
|
||||||
|
return 'Unauthorized'
|
||||||
|
|
||||||
|
# Sanitize arguments
|
||||||
dict = action_dict[request.method+' '+request.path]
|
dict = action_dict[request.method+' '+request.path]
|
||||||
if 'arguments' in dict: args = dict['arguments']
|
if 'arguments' in dict: args = dict['arguments']
|
||||||
else: args = {}
|
else: args = {}
|
||||||
|
@ -76,6 +65,8 @@ def http_exec(request):
|
||||||
del args[arg]
|
del args[arg]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
# Validate arguments
|
||||||
validated_args = {}
|
validated_args = {}
|
||||||
for key, value in request.args.items():
|
for key, value in request.args.items():
|
||||||
if key in args:
|
if key in args:
|
||||||
|
@ -88,6 +79,8 @@ def http_exec(request):
|
||||||
validated_args[key] = value
|
validated_args[key] = value
|
||||||
|
|
||||||
func = str_to_func(dict['function'])
|
func = str_to_func(dict['function'])
|
||||||
|
|
||||||
|
# Execute requested function
|
||||||
with YunoHostLDAP(password=request.getPassword()):
|
with YunoHostLDAP(password=request.getPassword()):
|
||||||
result = func(**validated_args)
|
result = func(**validated_args)
|
||||||
if result is None:
|
if result is None:
|
||||||
|
@ -95,6 +88,8 @@ def http_exec(request):
|
||||||
if win:
|
if win:
|
||||||
result['win'] = win
|
result['win'] = win
|
||||||
win = []
|
win = []
|
||||||
|
|
||||||
|
# Build response
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
request.setResponseCode(201, 'Created')
|
request.setResponseCode(201, 'Created')
|
||||||
elif request.method == 'DELETE':
|
elif request.method == 'DELETE':
|
||||||
|
@ -103,6 +98,8 @@ def http_exec(request):
|
||||||
request.setResponseCode(200, 'OK')
|
request.setResponseCode(200, 'OK')
|
||||||
|
|
||||||
except YunoHostError, error:
|
except YunoHostError, error:
|
||||||
|
|
||||||
|
# Set response code with function's raised code
|
||||||
server_errors = [1, 111, 169]
|
server_errors = [1, 111, 169]
|
||||||
client_errors = [13, 17, 22, 87, 122, 125, 167, 168]
|
client_errors = [13, 17, 22, 87, 122, 125, 167, 168]
|
||||||
if error.code in client_errors:
|
if error.code in client_errors:
|
||||||
|
@ -111,15 +108,16 @@ def http_exec(request):
|
||||||
request.setResponseCode(500, 'Internal Server Error')
|
request.setResponseCode(500, 'Internal Server Error')
|
||||||
result = { 'error' : error.message }
|
result = { 'error' : error.message }
|
||||||
|
|
||||||
request.setHeader('Content-Type', 'application/json')
|
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global action_dict
|
global action_dict
|
||||||
log.startLogging(sys.stdout)
|
global api
|
||||||
api = APIResource()
|
|
||||||
|
|
||||||
|
startLogging(open('/var/log/yunohost.log', 'a+')) # Log actions to API
|
||||||
|
|
||||||
|
# Load & parse yaml file
|
||||||
with open('action_map.yml') as f:
|
with open('action_map.yml') as f:
|
||||||
action_map = yaml.load(f)
|
action_map = yaml.load(f)
|
||||||
|
|
||||||
|
@ -131,7 +129,9 @@ def main():
|
||||||
if 'api' not in action_params:
|
if 'api' not in action_params:
|
||||||
action_params['api'] = 'GET /'+ category +'/'+ action
|
action_params['api'] = 'GET /'+ category +'/'+ action
|
||||||
method, path = action_params['api'].split(' ')
|
method, path = action_params['api'].split(' ')
|
||||||
|
# Register route
|
||||||
api.register(method, path, http_exec)
|
api.register(method, path, http_exec)
|
||||||
|
api.register('OPTIONS', path, http_exec)
|
||||||
action_dict[action_params['api']] = {
|
action_dict[action_params['api']] = {
|
||||||
'function': 'yunohost_'+ category +'.'+ category +'_'+ action,
|
'function': 'yunohost_'+ category +'.'+ category +'_'+ action,
|
||||||
'help' : action_params['help']
|
'help' : action_params['help']
|
||||||
|
@ -139,17 +139,28 @@ def main():
|
||||||
if 'arguments' in action_params:
|
if 'arguments' in action_params:
|
||||||
action_dict[action_params['api']]['arguments'] = action_params['arguments']
|
action_dict[action_params['api']]['arguments'] = action_params['arguments']
|
||||||
|
|
||||||
ldap_auth = LDAPHTTPAuth()
|
|
||||||
credentialFactory = BasicCredentialFactory("Restricted Area")
|
# Register only postinstall action if YunoHost isn't completely set up
|
||||||
resource = HTTPAuthSessionWrapper(Portal(SimpleRealm(api), [ldap_auth]), [credentialFactory])
|
|
||||||
try:
|
try:
|
||||||
with open('/etc/yunohost/installed') as f: pass
|
with open('/etc/yunohost/installed') as f: pass
|
||||||
except IOError:
|
except IOError:
|
||||||
resource = APIResource()
|
api = APIResource()
|
||||||
resource.register('POST', '/postinstall', http_exec)
|
api.register('POST', '/postinstall', http_exec)
|
||||||
reactor.listenTCP(6767, Site(resource, timeout=None))
|
api.register('OPTIONS', '/postinstall', http_exec)
|
||||||
reactor.run()
|
action_dict['POST /postinstall'] = {
|
||||||
|
'function' : 'yunohost_tools.tools_postinstall',
|
||||||
|
'help' : 'Execute post-install',
|
||||||
|
'arguments' : action_map['tools']['postinstall']['arguments']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
reactor.listenTCP(80, Site(api, timeout=None))
|
||||||
|
reactor.run()
|
||||||
|
else:
|
||||||
|
main()
|
||||||
|
application = service.Application("YunoHost API")
|
||||||
|
logfile = DailyLogFile("yunohost.log", "/var/log")
|
||||||
|
application.setComponent(ILogObserver, FileLogObserver(logfile).emit)
|
||||||
|
internet.TCPServer(6767, Site(api, timeout=None)).setServiceParent(application)
|
||||||
|
|
Loading…
Add table
Reference in a new issue