def doPost(request, session):
ROUTE_VERSION = '1.3.0' MIN_CLI = '1.0'
SECRET = None or '__IGN_CLI_SECRET__'
def _secretUnconfigured():
return SECRET is None or str(SECRET).startswith('_')
def _sha256Hex(s):
from java.security import MessageDigest
md = MessageDigest.getInstance('SHA-256')
md.update(str(s).encode('utf-8'))
digest = md.digest()
return ''.join(['%02x' % (b & 0xFF) for b in digest])
def _constantTimeEquals(a, b):
da = _sha256Hex(a)
db = _sha256Hex(b)
if len(da) != len(db):
return False
result = 0
for i in range(len(da)):
result |= ord(da[i]) ^ ord(db[i])
return result == 0
def _extractSecret(request):
headers = request.get('headers', {}) or {}
lowered = {}
for key, value in headers.items():
try:
lowered[key.lower()] = value
except AttributeError:
continue
presented = lowered.get('x-ignition-cli-secret', '') or ''
if presented:
return presented.strip()
auth = lowered.get('authorization', '') or ''
if auth.startswith('Bearer '):
return auth[7:].strip()
return ''
import json, traceback, time, sys
from StringIO import StringIO
data = request['data']
if isinstance(data, (str, unicode)): data = json.loads(data)
action = data.get('action')
def ok(payload):
return {'json': {'ok': True, 'data': payload}}
def err(code, message, tb=None):
e = {'code': code, 'message': message}
if tb:
e['traceback'] = tb
return {'json': {'ok': False, 'error': e}}
def jv(x, depth=0):
if depth > 12:
return str(x)
if x is None or isinstance(x, (bool, int, long, float)):
return x
if isinstance(x, (str, unicode)):
return str(x)
if isinstance(x, (list, tuple)):
return [jv(i, depth + 1) for i in x]
if isinstance(x, dict):
out = {}
for k in x.keys():
out[str(k)] = jv(x.get(k), depth + 1)
return out
try:
if hasattr(x, 'keySet'):
out = {}
for k in x.keySet():
out[str(k)] = jv(x.get(k), depth + 1)
return out
except:
pass
return str(x)
if _secretUnconfigured():
return err('secret_required', 'scriptExec route secret is not configured -- (re)deploy this route via ign webdev deploy')
presented = _extractSecret(request)
if not presented:
return err('secret_required', 'missing x-ignition-cli-secret (or Authorization: Bearer) header')
if not _constantTimeEquals(presented, str(SECRET)):
return err('secret_mismatch', 'scriptExec secret mismatch')
log = system.util.logger('ign-cli-scriptexec')
try:
if action == 'version':
return ok({'routeVersion': ROUTE_VERSION, 'minCli': MIN_CLI})
if action == 'exec':
code = data['code']
started = time.time()
g = {}
captured = StringIO()
oldStdout = sys.stdout
result = None
try:
sys.stdout = captured
try:
result = eval(code, g) except SyntaxError:
exec code in g result = g.get('_result')
finally:
sys.stdout = oldStdout
log.info('exec sha256=%s elapsedMs=%d' % (_sha256Hex(code)[:12], int((time.time() - started) * 1000)))
return ok({
'stdout': str(captured.getvalue()),
'result': jv(result),
'elapsedMs': int((time.time() - started) * 1000),
})
return err('unknown_action', 'unknown action: ' + str(action))
except:
return err('route_error', 'scriptExec route error', traceback.format_exc())