mirror of
https://github.com/billz/raspap-webgui.git
synced 2023-10-10 13:37:24 +02:00
842 lines
194 KiB
PHP
842 lines
194 KiB
PHP
|
<?php
|
||
|
// Web Console v0.9.7 (2016-11-05)
|
||
|
//
|
||
|
// Author: Nickolay Kovalev (http://nickola.ru)
|
||
|
// GitHub: https://github.com/nickola/web-console
|
||
|
// URL: http://web-console.org
|
||
|
|
||
|
// Disable login (don't ask for credentials, be careful)
|
||
|
// Example: $NO_LOGIN = true;
|
||
|
$NO_LOGIN = true;
|
||
|
|
||
|
// Single-user credentials
|
||
|
// Example: $USER = 'user'; $PASSWORD = 'password';
|
||
|
$USER = '';
|
||
|
$PASSWORD = '';
|
||
|
|
||
|
// Multi-user credentials
|
||
|
// Example: $ACCOUNTS = array('user1' => 'password1', 'user2' => 'password2');
|
||
|
$ACCOUNTS = array();
|
||
|
|
||
|
// Password hash algorithm (password must be hashed)
|
||
|
// Example: $PASSWORD_HASH_ALGORITHM = 'md5';
|
||
|
// $PASSWORD_HASH_ALGORITHM = 'sha256';
|
||
|
$PASSWORD_HASH_ALGORITHM = '';
|
||
|
|
||
|
// Home directory (multi-user mode supported)
|
||
|
// Example: $HOME_DIRECTORY = '/tmp';
|
||
|
// $HOME_DIRECTORY = array('user1' => '/home/user1', 'user2' => '/home/user2');
|
||
|
$HOME_DIRECTORY = '';
|
||
|
|
||
|
// Code below is automatically generated from different components
|
||
|
// For more information see: https://github.com/nickola/web-console
|
||
|
//
|
||
|
// Used components:
|
||
|
// - jQuery JavaScript Library: https://github.com/jquery/jquery
|
||
|
// - jQuery Terminal Emulator: https://github.com/jcubic/jquery.terminal
|
||
|
// - jQuery Mouse Wheel Plugin: https://github.com/brandonaaron/jquery-mousewheel
|
||
|
// - PHP JSON-RPC 2.0 Server/Client Implementation: https://github.com/sergeyfast/eazy-jsonrpc
|
||
|
// - Normalize.css: https://github.com/necolas/normalize.css
|
||
|
?>
|
||
|
<?php
|
||
|
|
||
|
|
||
|
/**
|
||
|
* JSON RPC Server for Eaze
|
||
|
*
|
||
|
* Reads $_GET['rawRequest'] or php://input for Request Data
|
||
|
* @link http://www.jsonrpc.org/specification
|
||
|
* @link http://dojotoolkit.org/reference-guide/1.8/dojox/rpc/smd.html
|
||
|
* @package Eaze
|
||
|
* @subpackage Model
|
||
|
* @author Sergeyfast
|
||
|
*/
|
||
|
class BaseJsonRpcServer {
|
||
|
|
||
|
const ParseError = -32700,
|
||
|
InvalidRequest = -32600,
|
||
|
MethodNotFound = -32601,
|
||
|
InvalidParams = -32602,
|
||
|
InternalError = -32603;
|
||
|
|
||
|
/**
|
||
|
* Exposed Instances
|
||
|
* @var object[] namespace => method
|
||
|
*/
|
||
|
protected $instances = array();
|
||
|
|
||
|
/**
|
||
|
* Decoded Json Request
|
||
|
* @var object|array
|
||
|
*/
|
||
|
protected $request;
|
||
|
|
||
|
/**
|
||
|
* Array of Received Calls
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $calls = array();
|
||
|
|
||
|
/**
|
||
|
* Array of Responses for Calls
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $response = array();
|
||
|
|
||
|
/**
|
||
|
* Has Calls Flag (not notifications)
|
||
|
* @var bool
|
||
|
*/
|
||
|
protected $hasCalls = false;
|
||
|
|
||
|
/**
|
||
|
* Is Batch Call in using
|
||
|
* @var bool
|
||
|
*/
|
||
|
private $isBatchCall = false;
|
||
|
|
||
|
/**
|
||
|
* Hidden Methods
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $hiddenMethods = array(
|
||
|
'execute', '__construct', 'registerinstance'
|
||
|
);
|
||
|
|
||
|
/**
|
||
|
* Content Type
|
||
|
* @var string
|
||
|
*/
|
||
|
public $ContentType = 'application/json';
|
||
|
|
||
|
/**
|
||
|
* Allow Cross-Domain Requests
|
||
|
* @var bool
|
||
|
*/
|
||
|
public $IsXDR = true;
|
||
|
|
||
|
/**
|
||
|
* Max Batch Calls
|
||
|
* @var int
|
||
|
*/
|
||
|
public $MaxBatchCalls = 10;
|
||
|
|
||
|
/**
|
||
|
* Error Messages
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $errorMessages = array(
|
||
|
self::ParseError => 'Parse error',
|
||
|
self::InvalidRequest => 'Invalid Request',
|
||
|
self::MethodNotFound => 'Method not found',
|
||
|
self::InvalidParams => 'Invalid params',
|
||
|
self::InternalError => 'Internal error',
|
||
|
);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Cached Reflection Methods
|
||
|
* @var ReflectionMethod[]
|
||
|
*/
|
||
|
private $reflectionMethods = array();
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Validate Request
|
||
|
* @return int error
|
||
|
*/
|
||
|
private function getRequest() {
|
||
|
$error = null;
|
||
|
|
||
|
do {
|
||
|
if ( array_key_exists( 'REQUEST_METHOD', $_SERVER ) && $_SERVER['REQUEST_METHOD'] != 'POST' ) {
|
||
|
$error = self::InvalidRequest;
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
$request = !empty( $_GET['rawRequest'] ) ? $_GET['rawRequest'] : file_get_contents( 'php://input' );
|
||
|
$this->request = json_decode( $request, false );
|
||
|
if ( $this->request === null ) {
|
||
|
$error = self::ParseError;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( $this->request === array() ) {
|
||
|
$error = self::InvalidRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// check for batch call
|
||
|
if ( is_array( $this->request ) ) {
|
||
|
if( count( $this->request ) > $this->MaxBatchCalls ) {
|
||
|
$error = self::InvalidRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
$this->calls = $this->request;
|
||
|
$this->isBatchCall = true;
|
||
|
} else {
|
||
|
$this->calls[] = $this->request;
|
||
|
}
|
||
|
} while ( false );
|
||
|
|
||
|
return $error;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get Error Response
|
||
|
* @param int $code
|
||
|
* @param mixed $id
|
||
|
* @param null $data
|
||
|
* @return array
|
||
|
*/
|
||
|
private function getError( $code, $id = null, $data = null ) {
|
||
|
return array(
|
||
|
'jsonrpc' => '2.0',
|
||
|
'id' => $id,
|
||
|
'error' => array(
|
||
|
'code' => $code,
|
||
|
'message' => isset( $this->errorMessages[$code] ) ? $this->errorMessages[$code] : $this->errorMessages[self::InternalError],
|
||
|
'data' => $data,
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Check for jsonrpc version and correct method
|
||
|
* @param object $call
|
||
|
* @return array|null
|
||
|
*/
|
||
|
private function validateCall( $call ) {
|
||
|
$result = null;
|
||
|
$error = null;
|
||
|
$data = null;
|
||
|
$id = is_object( $call ) && property_exists( $call, 'id' ) ? $call->id : null;
|
||
|
do {
|
||
|
if ( !is_object( $call ) ) {
|
||
|
$error = self::InvalidRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// hack for inputEx smd tester
|
||
|
if ( property_exists( $call, 'version' ) ) {
|
||
|
if ( $call->version == 'json-rpc-2.0' ) {
|
||
|
$call->jsonrpc = '2.0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !property_exists( $call, 'jsonrpc' ) || $call->jsonrpc != '2.0' ) {
|
||
|
$error = self::InvalidRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
$fullMethod = property_exists( $call, 'method' ) ? $call->method : '';
|
||
|
$methodInfo = explode( '.', $fullMethod, 2 );
|
||
|
$namespace = array_key_exists( 1, $methodInfo ) ? $methodInfo[0] : '';
|
||
|
$method = $namespace ? $methodInfo[1] : $fullMethod;
|
||
|
if ( !$method || !array_key_exists( $namespace, $this->instances ) || !method_exists( $this->instances[$namespace], $method ) || in_array( strtolower( $method ), $this->hiddenMethods ) ) {
|
||
|
$error = self::MethodNotFound;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( !array_key_exists( $fullMethod, $this->reflectionMethods ) ) {
|
||
|
$this->reflectionMethods[$fullMethod] = new ReflectionMethod( $this->instances[$namespace], $method );
|
||
|
}
|
||
|
|
||
|
/** @var $params array */
|
||
|
$params = property_exists( $call, 'params' ) ? $call->params : null;
|
||
|
$paramsType = gettype( $params );
|
||
|
if ( $params !== null && $paramsType != 'array' && $paramsType != 'object' ) {
|
||
|
$error = self::InvalidParams;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// check parameters
|
||
|
switch ( $paramsType ) {
|
||
|
case 'array':
|
||
|
$totalRequired = 0;
|
||
|
// doesn't hold required, null, required sequence of params
|
||
|
foreach ( $this->reflectionMethods[$fullMethod]->getParameters() as $param ) {
|
||
|
if ( !$param->isDefaultValueAvailable() ) {
|
||
|
$totalRequired++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( count( $params ) < $totalRequired ) {
|
||
|
$error = self::InvalidParams;
|
||
|
$data = sprintf( 'Check numbers of required params (got %d, expected %d)', count( $params ), $totalRequired );
|
||
|
}
|
||
|
break;
|
||
|
case 'object':
|
||
|
foreach ( $this->reflectionMethods[$fullMethod]->getParameters() as $param ) {
|
||
|
if ( !$param->isDefaultValueAvailable() && !array_key_exists( $param->getName(), $params ) ) {
|
||
|
$error = self::InvalidParams;
|
||
|
$data = $param->getName() . ' not found';
|
||
|
|
||
|
break 3;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 'NULL':
|
||
|
if ( $this->reflectionMethods[$fullMethod]->getNumberOfRequiredParameters() > 0 ) {
|
||
|
$error = self::InvalidParams;
|
||
|
$data = 'Empty required params';
|
||
|
break 2;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} while ( false );
|
||
|
|
||
|
if ( $error ) {
|
||
|
$result = array( $error, $id, $data );
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Process Call
|
||
|
* @param $call
|
||
|
* @return array|null
|
||
|
*/
|
||
|
private function processCall( $call ) {
|
||
|
$id = property_exists( $call, 'id' ) ? $call->id : null;
|
||
|
$params = property_exists( $call, 'params' ) ? $call->params : array();
|
||
|
$result = null;
|
||
|
$namespace = substr( $call->method, 0, strpos( $call->method, '.' ) );
|
||
|
|
||
|
try {
|
||
|
// set named parameters
|
||
|
if ( is_object( $params ) ) {
|
||
|
$newParams = array();
|
||
|
foreach ( $this->reflectionMethods[$call->method]->getParameters() as $param ) {
|
||
|
$paramName = $param->getName();
|
||
|
$defaultValue = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
|
||
|
$newParams[] = property_exists( $params, $paramName ) ? $params->$paramName : $defaultValue;
|
||
|
}
|
||
|
|
||
|
$params = $newParams;
|
||
|
}
|
||
|
|
||
|
// invoke
|
||
|
$result = $this->reflectionMethods[$call->method]->invokeArgs( $this->instances[$namespace], $params );
|
||
|
} catch ( Exception $e ) {
|
||
|
return $this->getError( $e->getCode(), $id, $e->getMessage() );
|
||
|
}
|
||
|
|
||
|
if ( !$id && $id !== 0 ) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return array(
|
||
|
'jsonrpc' => '2.0',
|
||
|
'result' => $result,
|
||
|
'id' => $id,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Create new Instance
|
||
|
* @param object $instance
|
||
|
*/
|
||
|
public function __construct( $instance = null ) {
|
||
|
if ( get_parent_class( $this ) ) {
|
||
|
$this->RegisterInstance( $this, '' );
|
||
|
} else if ( $instance ) {
|
||
|
$this->RegisterInstance( $instance, '' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Register Instance
|
||
|
* @param object $instance
|
||
|
* @param string $namespace default is empty string
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function RegisterInstance( $instance, $namespace = '' ) {
|
||
|
$this->instances[$namespace] = $instance;
|
||
|
$this->instances[$namespace]->errorMessages = $this->errorMessages;
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Handle Requests
|
||
|
*/
|
||
|
public function Execute() {
|
||
|
do {
|
||
|
// check for SMD Discovery request
|
||
|
if ( array_key_exists( 'smd', $_GET ) ) {
|
||
|
$this->response[] = $this->getServiceMap();
|
||
|
$this->hasCalls = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
$error = $this->getRequest();
|
||
|
if ( $error ) {
|
||
|
$this->response[] = $this->getError( $error );
|
||
|
$this->hasCalls = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
foreach ( $this->calls as $call ) {
|
||
|
$error = $this->validateCall( $call );
|
||
|
if ( $error ) {
|
||
|
$this->response[] = $this->getError( $error[0], $error[1], $error[2] );
|
||
|
$this->hasCalls = true;
|
||
|
} else {
|
||
|
$result = $this->processCall( $call );
|
||
|
if ( $result ) {
|
||
|
$this->response[] = $result;
|
||
|
$this->hasCalls = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} while ( false );
|
||
|
|
||
|
// flush response
|
||
|
if ( $this->hasCalls ) {
|
||
|
if ( !$this->isBatchCall ) {
|
||
|
$this->response = reset( $this->response );
|
||
|
}
|
||
|
|
||
|
if ( !headers_sent() ) {
|
||
|
// Set Content Type
|
||
|
if ( $this->ContentType ) {
|
||
|
header( 'Content-Type: ' . $this->ContentType );
|
||
|
}
|
||
|
|
||
|
// Allow Cross Domain Requests
|
||
|
if ( $this->IsXDR ) {
|
||
|
header( 'Access-Control-Allow-Origin: *' );
|
||
|
header( 'Access-Control-Allow-Headers: x-requested-with, content-type' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
echo json_encode( $this->response );
|
||
|
$this->resetVars();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get Doc Comment
|
||
|
* @param $comment
|
||
|
* @return string|null
|
||
|
*/
|
||
|
private function getDocDescription( $comment ) {
|
||
|
$result = null;
|
||
|
if ( preg_match( '/\*\s+([^@]*)\s+/s', $comment, $matches ) ) {
|
||
|
$result = str_replace( '*', "\n", trim( trim( $matches[1], '*' ) ) );
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get Service Map
|
||
|
* Maybe not so good realization of auto-discover via doc blocks
|
||
|
* @return array
|
||
|
*/
|
||
|
private function getServiceMap() {
|
||
|
$result = array(
|
||
|
'transport' => 'POST',
|
||
|
'envelope' => 'JSON-RPC-2.0',
|
||
|
'SMDVersion' => '2.0',
|
||
|
'contentType' => 'application/json',
|
||
|
'target' => !empty( $_SERVER['REQUEST_URI'] ) ? substr( $_SERVER['REQUEST_URI'], 0, strpos( $_SERVER['REQUEST_URI'], '?' ) ) : '',
|
||
|
'services' => array(),
|
||
|
'description' => '',
|
||
|
);
|
||
|
|
||
|
foreach( $this->instances as $namespace => $instance ) {
|
||
|
$rc = new ReflectionClass( $instance);
|
||
|
|
||
|
// Get Class Description
|
||
|
if ( $rcDocComment = $this->getDocDescription( $rc->getDocComment() ) ) {
|
||
|
$result['description'] .= $rcDocComment . PHP_EOL;
|
||
|
}
|
||
|
|
||
|
foreach ( $rc->getMethods() as $method ) {
|
||
|
/** @var ReflectionMethod $method */
|
||
|
if ( !$method->isPublic() || in_array( strtolower( $method->getName() ), $this->hiddenMethods ) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$methodName = ( $namespace ? $namespace . '.' : '' ) . $method->getName();
|
||
|
$docComment = $method->getDocComment();
|
||
|
|
||
|
$result['services'][$methodName] = array( 'parameters' => array() );
|
||
|
|
||
|
// set description
|
||
|
if ( $rmDocComment = $this->getDocDescription( $docComment ) ) {
|
||
|
$result['services'][$methodName]['description'] = $rmDocComment;
|
||
|
}
|
||
|
|
||
|
// @param\s+([^\s]*)\s+([^\s]*)\s*([^\s\*]*)
|
||
|
$parsedParams = array();
|
||
|
if ( preg_match_all( '/@param\s+([^\s]*)\s+([^\s]*)\s*([^\n\*]*)/', $docComment, $matches ) ) {
|
||
|
foreach ( $matches[2] as $number => $name ) {
|
||
|
$type = $matches[1][$number];
|
||
|
$desc = $matches[3][$number];
|
||
|
$name = trim( $name, '$' );
|
||
|
|
||
|
$param = array( 'type' => $type, 'description' => $desc );
|
||
|
$parsedParams[$name] = array_filter( $param );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// process params
|
||
|
foreach ( $method->getParameters() as $parameter ) {
|
||
|
$name = $parameter->getName();
|
||
|
$param = array( 'name' => $name, 'optional' => $parameter->isDefaultValueAvailable() );
|
||
|
if ( array_key_exists( $name, $parsedParams ) ) {
|
||
|
$param += $parsedParams[$name];
|
||
|
}
|
||
|
|
||
|
if ( $param['optional'] ) {
|
||
|
$param['default'] = $parameter->getDefaultValue();
|
||
|
}
|
||
|
|
||
|
$result['services'][$methodName]['parameters'][] = $param;
|
||
|
}
|
||
|
|
||
|
// set return type
|
||
|
if ( preg_match( '/@return\s+([^\s]+)\s*([^\n\*]+)/', $docComment, $matches ) ) {
|
||
|
$returns = array( 'type' => $matches[1], 'description' => trim( $matches[2] ) );
|
||
|
$result['services'][$methodName]['returns'] = array_filter( $returns );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Reset Local Class Vars after Execute
|
||
|
*/
|
||
|
private function resetVars() {
|
||
|
$this->response = $this->calls = array();
|
||
|
$this->hasCalls = $this->isBatchCall = false;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
?>
|
||
|
<?php
|
||
|
// Initializing
|
||
|
if (!isset($NO_LOGIN)) $NO_LOGIN = false;
|
||
|
if (!isset($ACCOUNTS)) $ACCOUNTS = array();
|
||
|
if (isset($USER) && isset($PASSWORD) && $USER && $PASSWORD) $ACCOUNTS[$USER] = $PASSWORD;
|
||
|
if (!isset($PASSWORD_HASH_ALGORITHM)) $PASSWORD_HASH_ALGORITHM = '';
|
||
|
if (!isset($HOME_DIRECTORY)) $HOME_DIRECTORY = '';
|
||
|
$IS_CONFIGURED = ($NO_LOGIN || count($ACCOUNTS) >= 1) ? true : false;
|
||
|
|
||
|
// Utilities
|
||
|
function is_empty_string($string) {
|
||
|
return strlen($string) <= 0;
|
||
|
}
|
||
|
|
||
|
function is_equal_strings($string1, $string2) {
|
||
|
return strcmp($string1, $string2) == 0;
|
||
|
}
|
||
|
|
||
|
function get_hash($algorithm, $string) {
|
||
|
return hash($algorithm, trim((string) $string));
|
||
|
}
|
||
|
|
||
|
// Command execution
|
||
|
function execute_command($command) {
|
||
|
$descriptors = array(
|
||
|
0 => array('pipe', 'r'), // STDIN
|
||
|
1 => array('pipe', 'w'), // STDOUT
|
||
|
2 => array('pipe', 'w') // STDERR
|
||
|
);
|
||
|
|
||
|
$process = proc_open($command . ' 2>&1', $descriptors, $pipes);
|
||
|
if (!is_resource($process)) die("Can't execute command.");
|
||
|
|
||
|
// Nothing to push to STDIN
|
||
|
fclose($pipes[0]);
|
||
|
|
||
|
$output = stream_get_contents($pipes[1]);
|
||
|
fclose($pipes[1]);
|
||
|
|
||
|
$error = stream_get_contents($pipes[2]);
|
||
|
fclose($pipes[2]);
|
||
|
|
||
|
// All pipes must be closed before "proc_close"
|
||
|
$code = proc_close($process);
|
||
|
|
||
|
return $output;
|
||
|
}
|
||
|
|
||
|
// Command parsing
|
||
|
function parse_command($command) {
|
||
|
$value = ltrim((string) $command);
|
||
|
|
||
|
if (!is_empty_string($value)) {
|
||
|
$values = explode(' ', $value);
|
||
|
$values_total = count($values);
|
||
|
|
||
|
if ($values_total > 1) {
|
||
|
$value = $values[$values_total - 1];
|
||
|
|
||
|
for ($index = $values_total - 2; $index >= 0; $index--) {
|
||
|
$value_item = $values[$index];
|
||
|
|
||
|
if (substr($value_item, -1) == '\\') $value = $value_item . ' ' . $value;
|
||
|
else break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
|
||
|
// RPC Server
|
||
|
class WebConsoleRPCServer extends BaseJsonRpcServer {
|
||
|
protected $home_directory = '';
|
||
|
|
||
|
private function error($message) {
|
||
|
throw new Exception($message);
|
||
|
}
|
||
|
|
||
|
// Authentication
|
||
|
private function authenticate_user($user, $password) {
|
||
|
$user = trim((string) $user);
|
||
|
$password = trim((string) $password);
|
||
|
|
||
|
if ($user && $password) {
|
||
|
global $ACCOUNTS, $PASSWORD_HASH_ALGORITHM;
|
||
|
|
||
|
if (isset($ACCOUNTS[$user]) && !is_empty_string($ACCOUNTS[$user])) {
|
||
|
if ($PASSWORD_HASH_ALGORITHM) $password = get_hash($PASSWORD_HASH_ALGORITHM, $password);
|
||
|
|
||
|
if (is_equal_strings($password, $ACCOUNTS[$user]))
|
||
|
return $user . ':' . get_hash('sha256', $password);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
throw new Exception("Incorrect user or password");
|
||
|
}
|
||
|
|
||
|
private function authenticate_token($token) {
|
||
|
global $NO_LOGIN;
|
||
|
if ($NO_LOGIN) return true;
|
||
|
|
||
|
$token = trim((string) $token);
|
||
|
$token_parts = explode(':', $token, 2);
|
||
|
|
||
|
if (count($token_parts) == 2) {
|
||
|
$user = trim((string) $token_parts[0]);
|
||
|
$password_hash = trim((string) $token_parts[1]);
|
||
|
|
||
|
if ($user && $password_hash) {
|
||
|
global $ACCOUNTS;
|
||
|
|
||
|
if (isset($ACCOUNTS[$user]) && !is_empty_string($ACCOUNTS[$user])) {
|
||
|
$real_password_hash = get_hash('sha256', $ACCOUNTS[$user]);
|
||
|
if (is_equal_strings($password_hash, $real_password_hash)) return $user;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
throw new Exception("Incorrect user or password");
|
||
|
}
|
||
|
|
||
|
private function get_home_directory($user) {
|
||
|
global $HOME_DIRECTORY;
|
||
|
|
||
|
if (is_string($HOME_DIRECTORY)) {
|
||
|
if (!is_empty_string($HOME_DIRECTORY)) return $HOME_DIRECTORY;
|
||
|
}
|
||
|
else if (is_string($user) && !is_empty_string($user) && isset($HOME_DIRECTORY[$user]) && !is_empty_string($HOME_DIRECTORY[$user]))
|
||
|
return $HOME_DIRECTORY[$user];
|
||
|
|
||
|
return getcwd();
|
||
|
}
|
||
|
|
||
|
// Environment
|
||
|
private function get_environment() {
|
||
|
$hostname = function_exists('gethostname') ? gethostname() : null;
|
||
|
return array('path' => getcwd(), 'hostname' => $hostname);
|
||
|
}
|
||
|
|
||
|
private function set_environment($environment) {
|
||
|
$environment = !empty($environment) ? (array) $environment : array();
|
||
|
$path = (isset($environment['path']) && !is_empty_string($environment['path'])) ? $environment['path'] : $this->home_directory;
|
||
|
|
||
|
if (!is_empty_string($path)) {
|
||
|
if (is_dir($path)) {
|
||
|
if (!@chdir($path)) return array('output' => "Unable to change directory to current working directory, updating current directory",
|
||
|
'environment' => $this->get_environment());
|
||
|
}
|
||
|
else return array('output' => "Current working directory not found, updating current directory",
|
||
|
'environment' => $this->get_environment());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Initialization
|
||
|
private function initialize($token, $environment) {
|
||
|
$user = $this->authenticate_token($token);
|
||
|
$this->home_directory = $this->get_home_directory($user);
|
||
|
$result = $this->set_environment($environment);
|
||
|
|
||
|
if ($result) return $result;
|
||
|
}
|
||
|
|
||
|
// Methods
|
||
|
public function login($user, $password) {
|
||
|
$result = array('token' => $this->authenticate_user($user, $password),
|
||
|
'environment' => $this->get_environment());
|
||
|
|
||
|
$home_directory = $this->get_home_directory($user);
|
||
|
if (!is_empty_string($home_directory)) {
|
||
|
if (is_dir($home_directory)) $result['environment']['path'] = $home_directory;
|
||
|
else $result['output'] = "Home directory not found: ". $home_directory;
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
public function cd($token, $environment, $path) {
|
||
|
$result = $this->initialize($token, $environment);
|
||
|
if ($result) return $result;
|
||
|
|
||
|
$path = trim((string) $path);
|
||
|
if (is_empty_string($path)) $path = $this->home_directory;
|
||
|
|
||
|
if (!is_empty_string($path)) {
|
||
|
if (is_dir($path)) {
|
||
|
if (!@chdir($path)) return array('output' => "cd: ". $path . ": Unable to change directory");
|
||
|
}
|
||
|
else return array('output' => "cd: ". $path . ": No such directory");
|
||
|
}
|
||
|
|
||
|
return array('environment' => $this->get_environment());
|
||
|
}
|
||
|
|
||
|
public function completion($token, $environment, $pattern, $command) {
|
||
|
$result = $this->initialize($token, $environment);
|
||
|
if ($result) return $result;
|
||
|
|
||
|
$scan_path = '';
|
||
|
$completion_prefix = '';
|
||
|
$completion = array();
|
||
|
|
||
|
if (!empty($pattern)) {
|
||
|
if (!is_dir($pattern)) {
|
||
|
$pattern = dirname($pattern);
|
||
|
if ($pattern == '.') $pattern = '';
|
||
|
}
|
||
|
|
||
|
if (!empty($pattern)) {
|
||
|
if (is_dir($pattern)) {
|
||
|
$scan_path = $completion_prefix = $pattern;
|
||
|
if (substr($completion_prefix, -1) != '/') $completion_prefix .= '/';
|
||
|
}
|
||
|
}
|
||
|
else $scan_path = getcwd();
|
||
|
}
|
||
|
else $scan_path = getcwd();
|
||
|
|
||
|
if (!empty($scan_path)) {
|
||
|
// Loading directory listing
|
||
|
$completion = array_values(array_diff(scandir($scan_path), array('..', '.')));
|
||
|
natsort($completion);
|
||
|
|
||
|
// Prefix
|
||
|
if (!empty($completion_prefix) && !empty($completion)) {
|
||
|
foreach ($completion as &$value) $value = $completion_prefix . $value;
|
||
|
}
|
||
|
|
||
|
// Pattern
|
||
|
if (!empty($pattern) && !empty($completion)) {
|
||
|
// For PHP version that does not support anonymous functions (available since PHP 5.3.0)
|
||
|
function filter_pattern($value) {
|
||
|
global $pattern;
|
||
|
return !strncmp($pattern, $value, strlen($pattern));
|
||
|
}
|
||
|
|
||
|
$completion = array_values(array_filter($completion, 'filter_pattern'));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return array('completion' => $completion);
|
||
|
}
|
||
|
|
||
|
public function run($token, $environment, $command) {
|
||
|
$result = $this->initialize($token, $environment);
|
||
|
if ($result) return $result;
|
||
|
|
||
|
$output = ($command && !is_empty_string($command)) ? execute_command($command) : '';
|
||
|
if ($output && substr($output, -1) == "\n") $output = substr($output, 0, -1);
|
||
|
|
||
|
return array('output' => $output);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Processing request
|
||
|
if (array_key_exists('REQUEST_METHOD', $_SERVER) && $_SERVER['REQUEST_METHOD'] == 'POST') {
|
||
|
$rpc_server = new WebConsoleRPCServer();
|
||
|
$rpc_server->Execute();
|
||
|
}
|
||
|
else if (!$IS_CONFIGURED) {
|
||
|
?>
|
||
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="utf-8" />
|
||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||
|
<title>Web Console</title>
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
<meta name="description" content="Web Console (http://www.web-console.org)" />
|
||
|
<meta name="author" content="Nickolay Kovalev (http://resume.nickola.ru)" />
|
||
|
<meta name="robots" content="none" />
|
||
|
<style type="text/css">html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:0;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}.cmd .format,.cmd .prompt,.cmd .prompt div,.terminal .terminal-output .format,.terminal .terminal-output div div{display:inline-block}.cmd,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6,.terminal pre{margin:0}.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6{line-height:1.2em}.cmd .clipboard{position:absolute;left:-16px;top:0;width:10px;height:16px;background:0 0;border:0;color:transparent;outline:0;padding:0;resize:none;z-index:0;overflow:hidden}.terminal .error{color:red}.terminal{padding:10px;position:relative;overflow:auto}.cmd{padding:0;height:1.3em;position:relative}.cmd .cursor.blink,.cmd .inverted,.terminal .inverted{background-color:#aaa;color:#000}.cmd .cursor.blink{-webkit-animation:terminal-blink 1s infinite steps(1,start);-moz-animation:terminal-blink 1s infinite steps(1,start);-ms-animation:terminal-blink 1s infinite steps(1,start);animation:terminal-blink 1s infinite steps(1,start)}@-webkit-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@-ms-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@-moz-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}.cmd .prompt,.terminal .terminal-output div div{display:block;line-height:14px;height:auto}.cmd .prompt{float:left}.cmd,.terminal{background-color:#000}.terminal-output>div{min-height:14px}.terminal-output>div>div *{word-wrap:break-word}.terminal .terminal-output div span{display:inline-block}.cmd span{float:left}.cmd div,.cmd span,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h
|
||
|
</head>
|
||
|
<body>
|
||
|
<div class="configure">
|
||
|
<p>Web Console must be configured before use:</p>
|
||
|
<ul>
|
||
|
<li>Open Web Console PHP file in your favorite text editor.</li>
|
||
|
<li>At the beginning of the file enter your <span class="variable">$USER</span> and <span class="variable">$PASSWORD</span> credentials, edit any other settings that you like (see description in the comments).</li>
|
||
|
<li>Upload changed file to the web server and open it in the browser.</li>
|
||
|
</ul>
|
||
|
<p>For more information visit Web Console website: <a href="http://web-console.org">http://web-console.org</a></p>
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|
||
|
<?php
|
||
|
}
|
||
|
else { ?>
|
||
|
<!DOCTYPE html>
|
||
|
<html class="no-js">
|
||
|
<head>
|
||
|
<meta charset="utf-8" />
|
||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||
|
<title>Web Console</title>
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
<meta name="description" content="Web Console (http://www.web-console.org)" />
|
||
|
<meta name="author" content="Nickolay Kovalev (http://resume.nickola.ru)" />
|
||
|
<meta name="robots" content="none" />
|
||
|
<style type="text/css">html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:0;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}.cmd .format,.cmd .prompt,.cmd .prompt div,.terminal .terminal-output .format,.terminal .terminal-output div div{display:inline-block}.cmd,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6,.terminal pre{margin:0}.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h6{line-height:1.2em}.cmd .clipboard{position:absolute;left:-16px;top:0;width:10px;height:16px;background:0 0;border:0;color:transparent;outline:0;padding:0;resize:none;z-index:0;overflow:hidden}.terminal .error{color:red}.terminal{padding:10px;position:relative;overflow:auto}.cmd{padding:0;height:1.3em;position:relative}.cmd .cursor.blink,.cmd .inverted,.terminal .inverted{background-color:#aaa;color:#000}.cmd .cursor.blink{-webkit-animation:terminal-blink 1s infinite steps(1,start);-moz-animation:terminal-blink 1s infinite steps(1,start);-ms-animation:terminal-blink 1s infinite steps(1,start);animation:terminal-blink 1s infinite steps(1,start)}@-webkit-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@-ms-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@-moz-keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}@keyframes terminal-blink{0%,100%{background-color:#000;color:#aaa}50%{background-color:#bbb;color:#000}}.cmd .prompt,.terminal .terminal-output div div{display:block;line-height:14px;height:auto}.cmd .prompt{float:left}.cmd,.terminal{background-color:#000}.terminal-output>div{min-height:14px}.terminal-output>div>div *{word-wrap:break-word}.terminal .terminal-output div span{display:inline-block}.cmd span{float:left}.cmd div,.cmd span,.terminal h1,.terminal h2,.terminal h3,.terminal h4,.terminal h5,.terminal h
|
||
|
<script type="text/javascript">!function(a,b){function c(a){return K.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}function d(a){if(!tb[a]){var b=H.body,c=K("<"+a+">").appendTo(b),d=c.css("display");c.remove(),("none"===d||""===d)&&(pb||(pb=H.createElement("iframe"),pb.frameBorder=pb.width=pb.height=0),b.appendChild(pb),qb&&pb.createElement||(qb=(pb.contentWindow||pb.contentDocument).document,qb.write(("CSS1Compat"===H.compatMode?"<!doctype html>":"")+"<html><body>"),qb.close()),c=qb.createElement(a),qb.body.appendChild(c),d=K.css(c,"display"),b.removeChild(pb)),tb[a]=d}return tb[a]}function e(a,b){var c={};return K.each(wb.concat.apply([],wb.slice(0,b)),function(){c[this]=a}),c}function f(){sb=b}function g(){return setTimeout(f,0),sb=K.now()}function h(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function i(){try{return new a.XMLHttpRequest}catch(b){}}function j(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d,e,f,g,h,i,j,k,l=a.dataTypes,m={},n=l.length,o=l[0];for(d=1;n>d;d++){if(1===d)for(e in a.converters)"string"==typeof e&&(m[e.toLowerCase()]=a.converters[e]);if(g=o,o=l[d],"*"===o)o=g;else if("*"!==g&&g!==o){if(h=g+" "+o,i=m[h]||m["* "+o],!i){k=b;for(j in m)if(f=j.split(" "),(f[0]===g||"*"===f[0])&&(k=m[f[1]+" "+o])){j=m[j],j===!0?i=k:k===!0&&(i=j);break}}!i&&!k&&K.error("No conversion from "+h.replace(" "," to ")),i!==!0&&(c=i?i(c):k(j(c)))}}return c}function k(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);for(;"*"===j[0];)j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}return g?(g!==j[0]&&j.unshift(g),d[g]):void 0}function l(a,b,c,d){if(K.isArray(b))K.each(b,function(b,e){c||Ta.test(a)?d(a,e):l(a+"["+("object"==typeof e||K.isArray(e)?b:"")+"]",e,c,d)});else if(c||null==b||"object"!=typeof b)d(a,b);else for(var e in b)l(a+"["+e+"]",b[e],c,d)}function m(a,c){var d,e,f=K.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&K.extend(!0,a,e)}function n(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;for(var h,i=a[f],j=0,k=i?i.length:0,l=a===gb;k>j&&(l||!h);j++)h=i[j](c,d,e),"string"==typeof h&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=n(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=n(a,c,d,e,"*",g)),h}function o(a){return function(b,c){if("string"!=typeof b&&(c=b,b="*"),K.isFunction(c))for(var d,e,f,g=b.toLowerCase().split(cb),h=0,i=g.length;i>h;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function p(a,b,c){var d="width"===b?a.offsetWidth:a.offsetHeight,e="width"===b?Oa:Pa,f=0,g=e.length;if(d>0){if("border"!==c)for(;g>f;f++)c||(d-=parseFloat(K.css(a,"padding"+e[f]))||0),"margin"===c?d+=parseFloat(K.css(a,c+e[f]))||0:d-=parseFloat(K.css(a,"border"+e[f]+"Width"))||0;return d+"px"}if(d=Ea(a,b,b),(0>d||null==d)&&(d=a.style[b]||0),d=parseFloat(d)||0,c)for(;g>f;f++)d+=parseFloat(K.css(a,"padding"+e[f]))||0,"padding"!==c&&(d+=parseFloat(K.css(a,"border"+e[f]+"Width"))||0),"margin"===c&&(d+=parseFloat(K.css(a,c+e[f]))||0);return d+"px"}function q(a,b){b.src?K.ajax({url:b.src,async:!1,dataType:"script"}):K.globalEval((b.text||b.textContent||b.innerHTML||"").replace(Ba,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function r(a){var b=H.createElement("div");return Da.appendChild(b),b.innerHTML=a.outerHTML,b.firstChild}function s(a){var b=(a.nodeName||"").toLowerCase();"input"===b?t(a):"script"!==b&&"undefined"!=typeof a.getElementsByTagName&&K.grep(a.getElementsByTagName("input"),t)}function t(a){("checkbox"===a.type||"radio"===a.type)&&(a.defaultChecked=a.checked)}function u(a){return"undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName("*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll("*"):[]}function v(a,b){var c;1===b.nodeType&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),"object"===c?b
|
||
|
},ha=function(a){return K.event.special.hover?a:a.replace(aa,"mouseenter$1 mouseleave$1")};K.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q;if(3!==a.nodeType&&8!==a.nodeType&&c&&d&&(g=K._data(a))){for(d.handler&&(o=d,d=o.handler),d.guid||(d.guid=K.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return"undefined"==typeof K||a&&K.event.triggered===a.type?b:K.event.dispatch.apply(h.elem,arguments)},h.elem=a),c=K.trim(ha(c)).split(" "),j=0;j<c.length;j++)k=_.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),q=K.event.special[l]||{},l=(f?q.delegateType:q.bindType)||l,q=K.event.special[l]||{},n=K.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,quick:fa(f),namespace:m.join(".")},o),p=i[l],p||(p=i[l]=[],p.delegateCount=0,q.setup&&q.setup.call(a,e,m,h)!==!1||(a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h))),q.add&&(q.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?p.splice(p.delegateCount++,0,n):p.push(n),K.event.global[l]=!0;a=null}},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r=K.hasData(a)&&K._data(a);if(r&&(m=r.events)){for(b=K.trim(ha(b||"")).split(" "),f=0;f<b.length;f++)if(g=_.exec(b[f])||[],h=i=g[1],j=g[2],h){for(n=K.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,p=m[h]||[],k=p.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null,l=0;l<p.length;l++)q=p[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||"**"===d&&q.selector)&&(p.splice(l--,1),q.selector&&p.delegateCount--,n.remove&&n.remove.call(a,q));0===p.length&&k!==p.length&&((!n.teardown||n.teardown.call(a,j)===!1)&&K.removeEvent(a,h,r.handle),delete m[h])}else for(h in m)K.event.remove(a,h+b[f],c,d,!0);K.isEmptyObject(m)&&(o=r.handle,o&&(o.elem=null),K.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,f){if(!e||3!==e.nodeType&&8!==e.nodeType){var g,h,i,j,k,l,m,n,o,p,q=c.type||c,r=[];if(da.test(q+K.event.triggered))return;if(q.indexOf("!")>=0&&(q=q.slice(0,-1),h=!0),q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),(!e||K.event.customEvent[q])&&!K.event.global[q])return;if(c="object"==typeof c?c[K.expando]?c:new K.Event(q,c):new K.Event(q),c.type=q,c.isTrigger=!0,c.exclusive=h,c.namespace=r.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,l=q.indexOf(":")<0?"on"+q:"",!e){g=K.cache;for(i in g)g[i].events&&g[i].events[q]&&K.event.trigger(c,d,g[i].handle.elem,!0);return}if(c.result=b,c.target||(c.target=e),d=null!=d?K.makeArray(d):[],d.unshift(c),m=K.event.special[q]||{},m.trigger&&m.trigger.apply(e,d)===!1)return;if(o=[[e,m.bindType||q]],!f&&!m.noBubble&&!K.isWindow(e)){for(p=m.delegateType||q,j=da.test(p+q)?e:e.parentNode,k=null;j;j=j.parentNode)o.push([j,p]),k=j;k&&k===e.ownerDocument&&o.push([k.defaultView||k.parentWindow||a,p])}for(i=0;i<o.length&&!c.isPropagationStopped();i++)j=o[i][0],c.type=o[i][1],n=(K._data(j,"events")||{})[c.type]&&K._data(j,"handle"),n&&n.apply(j,d),n=l&&j[l],n&&K.acceptData(j)&&n.apply(j,d)===!1&&c.preventDefault();return c.type=q,!f&&!c.isDefaultPrevented()&&(!m._default||m._default.apply(e.ownerDocument,d)===!1)&&("click"!==q||!K.nodeName(e,"a"))&&K.acceptData(e)&&l&&e[q]&&("focus"!==q&&"blur"!==q||0!==c.target.offsetWidth)&&!K.isWindow(e)&&(k=e[l],k&&(e[l]=null),K.event.triggered=q,e[q](),K.event.triggered=b,k&&(e[l]=k)),c.result}},dispatch:function(c){c=K.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n=(K._data(this,"events")||{})[c.type]||[],o=n.delegateCount,p=[].slice.call(arguments,0),q=!c.exclusive&&!c.namespace,r=[];if(p[0]=c,c.delegateTarget=this,o&&!c.target.disabled&&(!c.button||"click"!==c.type))for(g=K(this),g.context=this.ownerDocument||this,f=c.target;f!=this;f=f.parentNode||this){for(i={},k=[],g[0]=f,d=0;o>d;d++)l=n[d],m=l.selector,i[m]===b&&(i[m]=l.quick?ga(f,l.quick):g.is(m)),i[m]&&k.push(l);k.length&&r.push({elem:f,matches:k})}for(n.length>o&&r.push
|
||
|
if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=K.clean(arguments);return a.push.apply(a,this.toArray()),this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);return a.push.apply(a,K.clean(arguments)),a}},remove:function(a,b){for(var c,d=0;null!=(c=this[d]);d++)(!a||K.filter(a,[c]).length)&&(!b&&1===c.nodeType&&(K.cleanData(c.getElementsByTagName("*")),K.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)for(1===a.nodeType&&K.cleanData(a.getElementsByTagName("*"));a.firstChild;)a.removeChild(a.firstChild);return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return K.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&1===this[0].nodeType?this[0].innerHTML.replace(qa,""):null;if("string"!=typeof a||wa.test(a)||!K.support.leadingWhitespace&&ra.test(a)||Ca[(ta.exec(a)||["",""])[1].toLowerCase()])K.isFunction(a)?this.each(function(b){var c=K(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(sa,"<$1></$2>");try{for(var c=0,d=this.length;d>c;c++)1===this[c].nodeType&&(K.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}return this},replaceWith:function(a){return this[0]&&this[0].parentNode?K.isFunction(a)?this.each(function(b){var c=K(this),d=c.html();c.replaceWith(a.call(this,b,d))}):("string"!=typeof a&&(a=K(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;K(this).remove(),b?K(b).before(a):K(c).append(a)})):this.length?this.pushStack(K(K.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,f,g,h,i=a[0],j=[];if(!K.support.checkClone&&3===arguments.length&&"string"==typeof i&&za.test(i))return this.each(function(){K(this).domManip(a,c,d,!0)});if(K.isFunction(i))return this.each(function(e){var f=K(this);a[0]=i.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){if(h=i&&i.parentNode,e=K.support.parentNode&&h&&11===h.nodeType&&h.childNodes.length===this.length?{fragment:h}:K.buildFragment(a,this,j),g=e.fragment,f=1===g.childNodes.length?g=g.firstChild:g.firstChild,f){c=c&&K.nodeName(f,"tr");for(var k=0,l=this.length,m=l-1;l>k;k++)d.call(c?x(this[k],f):this[k],e.cacheable||l>1&&m>k?K.clone(g,!0,!0):g)}j.length&&K.each(j,q)}return this}}),K.buildFragment=function(a,b,c){var d,e,f,g,h=a[0];return b&&b[0]&&(g=b[0].ownerDocument||b[0]),g.createDocumentFragment||(g=H),1===a.length&&"string"==typeof h&&h.length<512&&g===H&&"<"===h.charAt(0)&&!xa.test(h)&&(K.support.checkClone||!za.test(h))&&(K.support.html5Clone||!ya.test(h))&&(e=!0,f=K.fragments[h],f&&1!==f&&(d=f)),d||(d=g.createDocumentFragment(),K.clean(a,g,d,c)),e&&(K.fragments[h]=f?d:1),{fragment:d,cacheable:e}},K.fragments={},K.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){K.fn[a]=function(c){var d=[],e=K(c),f=1===this.length&&this[0].parentNode;if(f&&11===f.nodeType&&1===f.childNodes.length&&1===e.length)return e[b](this[0]),this;for(var g=0,h=e.length;h>g;g++){var i=(g>0?this.clone(!0):this).get();K(e[g])[b](i),d=d.concat(i)}return this.pushStack(d,a,e.selector)}}),K.extend({clone:function(a,b,c){var d,e,f,g=K.support.html5Clone||!ya.test("<"+a.nodeName)?a.cloneNode(!0):r(a);if(!(K.support.noCloneEvent&&K.support.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||K.isXMLDoc(a)))for(v(a,g),d=u(a),e=u(g),f=0;d[f];++f)e[f]&&v(d[f],e[f]);if(b&&(w(a,g),c))for(d=u(a),e=u(g),f=0;d[f];++f)w(d[f],e[f]);return d=e=null,g},clean:function(a,b,c,d){var e;b=b||H,"undefined"==typeof b.createElement&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||H);for(var f,g,h=[],i=0;null!=(g=a[i]);i++)if("number"==
|
||
|
f.push(h[1])}c[2]=f}else e|=2;if(3===e)throw"[sprintf] mixing positional and named placeholders is not (yet) supported";d.push(c)}b=b.substring(c[0].length)}return d};var e=function(a,b,c){return c=b.slice(0),c.splice(0,0,a),d.apply(null,c)};a.sprintf=d,a.vsprintf=e}("undefined"!=typeof global?global:window),function(a,b){"use strict";function c(a,b){var c;if("string"==typeof a&&"string"==typeof b)return localStorage[a]=b,!0;if("object"==typeof a&&"undefined"==typeof b){for(c in a)a.hasOwnProperty(c)&&(localStorage[c]=a[c]);return!0}return!1}function d(a,b){var c,d,e;if(c=new Date,c.setTime(c.getTime()+31536e6),d="; expires="+c.toGMTString(),"string"==typeof a&&"string"==typeof b)return document.cookie=a+"="+b+d+"; path=/",!0;if("object"==typeof a&&"undefined"==typeof b){for(e in a)a.hasOwnProperty(e)&&(document.cookie=e+"="+a[e]+d+"; path=/");return!0}return!1}function e(a){return localStorage[a]}function f(a){var b,c,d,e;for(b=a+"=",c=document.cookie.split(";"),d=0;d<c.length;d++){for(e=c[d];" "===e.charAt(0);)e=e.substring(1,e.length);if(0===e.indexOf(b))return e.substring(b.length,e.length)}return null}function g(a){return delete localStorage[a]}function h(a){return d(a,"",-1)}function i(a,b){var c=[],d=a.length;if(b>d)return[a];if(0>b)throw new Error("str_parts: length can't be negative");for(var e=0;d>e;e+=b)c.push(a.substring(e,e+b));return c}function j(b){var c=b?[b]:[],d=0;a.extend(this,{get:function(){return c},rotate:function(){return c.filter(Boolean).length?1===c.length?c[0]:(d===c.length-1?d=0:++d,c[d]?c[d]:this.rotate()):void 0},length:function(){return c.length},remove:function(a){delete c[a]},set:function(a){for(var b=c.length;b--;)if(c[b]===a)return void(d=b);this.append(a)},front:function(){if(c.length){for(var a=d,b=!1;!c[a];)if(a++,a>c.length){if(b)break;a=0,b=!0}return c[a]}},append:function(a){c.push(a)}})}function k(b){var c=b instanceof Array?b:b?[b]:[];a.extend(this,{data:function(){return c},map:function(b){return a.map(c,b)},size:function(){return c.length},pop:function(){if(0===c.length)return null;var a=c[c.length-1];return c=c.slice(0,c.length-1),a},push:function(a){return c=c.concat([a]),a},top:function(){return c.length>0?c[c.length-1]:null},clone:function(){return new k(c.slice(0))}})}function l(b,c){var d=!0,e="";"string"==typeof b&&""!==b&&(e=b+"_"),e+="commands";var f=a.Storage.get(e);f=f?a.parseJSON(f):[];var g=f.length-1;a.extend(this,{append:function(b){d&&f[f.length-1]!==b&&(f.push(b),c&&f.length>c&&(f=f.slice(-c)),g=f.length-1,a.Storage.set(e,a.json_stringify(f)))},data:function(){return f},reset:function(){g=f.length-1},last:function(){return f[f.length-1]},end:function(){return g===f.length-1},position:function(){return g},current:function(){return f[g]},next:function(){return g<f.length-1&&++g,-1!==g?f[g]:void 0},previous:function(){var a=g;return g>0&&--g,-1!==a?f[g]:void 0},clear:function(){f=[],this.purge()},enabled:function(){return d},enable:function(){d=!0},purge:function(){a.Storage.remove(e)},disable:function(){d=!1}})}function m(b){return a("<div>"+a.terminal.strip(b)+"</div>").text().length}function n(b,c){var d=c(b);if(d.length){var e=d.shift(),f=new RegExp("^"+a.terminal.escape_regex(e)),g=b.replace(f,"").trim();return{command:b,name:e,args:d,rest:g}}return{command:b,name:"",args:[],rest:""}}function o(){var b=a('<div class="terminal temp"><div class="cmd"><span class="cursor"> </span></div></div>').appendTo("body"),c=b.find("span"),d={width:c.width(),height:c.outerHeight()};return b.remove(),d}function p(b){var c=a('<div class="terminal wrap"><span class="cursor"> </span></div>').appendTo("body").css("padding",0),d=c.find("span"),e=d[0].getBoundingClientRect().width,f=Math.floor(b.width()/e);if(c.remove(),s(b)){var g=20,h=b.innerWidth()-b.width();f-=Math.ceil((g-h/2)/(e-1))}return f}function q(a){return Math.floor(a.height()/o().height)}function r(){if(window.getSelection||document.getSelection){var a=(window.getSelection||document.getSelection)();return a.text?a.text:a.toString()}return document.selection?document
|
||
|
var g=b.token();g?d(a.name,[g].concat(a.args)):b.error("[AUTH] "+ya.noTokenError)}else d(a.name,a.args)}}}function j(c,d,f,g){return function(h,i){if(""!==h){var k;try{k=e(h)}catch(l){return void ha.error(l.toString())}var m=c[k.name],n=a.type(m);if("function"===n){if(!d||m.length===k.args.length)return m.apply(ha,k.args);ha.error("[Arity] "+sprintf(ya.wrongArity,k.name,m.length,k.args.length))}else if("object"===n||"string"===n){var o=[];"object"===n&&(o=Object.keys(m),m=j(m,d,f)),i.push(m,{prompt:k.name+"> ",name:k.name,completion:"object"===n?o:b})}else a.isFunction(g)?g(h,ha):a.isFunction(xa.onCommandNotFound)?xa.onCommandNotFound(h,ha):i.error(sprintf(ya.commandNotFound,k.name))}}}function l(b,c,d){ha.resume(),a.isFunction(xa.onAjaxError)?xa.onAjaxError.call(ha,b,c,d):"abort"!==c&&ha.error("[AJAX] "+c+" - "+ya.serverResponse+": \n"+a.terminal.escape_brackets(b.responseText))}function m(b,c,d){a.jrpc(b,"system.describe",[],function(e){if(e.procs){var g={};a.each(e.procs,function(d,e){g[e.name]=function(){var d=c&&"help"!=e.name,g=Array.prototype.slice.call(arguments),i=g.length+(d?1:0);if(xa.checkArity&&e.params&&e.params.length!==i)ha.error("[Arity] "+sprintf(ya.wrongArity,e.name,e.params.length,i));else{if(ha.pause(),d){var j=ha.token(!0);j?g=[j].concat(g):ha.error("[AUTH] "+ya.noTokenError)}a.jrpc(b,e.name,g,function(b){b.error?h(b.error):a.isFunction(xa.processRPCResponse)?xa.processRPCResponse.call(ha,b.result,ha):f(b.result),ha.resume()},l)}}}),g.help=g.help||function(b){if("undefined"==typeof b)ha.echo("Available commands: "+e.procs.map(function(a){return a.name}).join(", ")+", help");else{var c=!1;if(a.each(e.procs,function(a,d){if(d.name==b){c=!0;var e="";return e+="[[bu;#fff;]"+d.name+"]",d.params&&(e+=" "+d.params.join(" ")),d.help&&(e+="\n"+d.help),ha.echo(e),!1}}),!c)if("help"==b)ha.echo("[[bu;#fff;]help] [method]\ndisplay help for the method or list of methods if not specified");else{var d="Method `"+b.toString()+"' not found ";ha.error(d)}}},d(g)}else d(null)},function(){d(null)})}function o(b,c,d){d=d||a.noop;var e,f,g=a.type(b),h={},k=0;if("array"===g)e={},function l(b,d){if(b.length){var g=b[0],h=b.slice(1),j=a.type(g);"string"===j?(k++,ha.pause(),xa.ignoreSystemDescribe?(1===k?f=i(g,c):ha.error(ya.oneRPCWithIgnore),l(h,d)):m(g,c,function(b){b&&a.extend(e,b),ha.resume(),l(h,d)})):"function"===j?(f?ha.error(ya.oneInterpreterFunction):f=g,l(h,d)):"object"===j&&(a.extend(e,g),l(h,d))}else d()}(b,function(){d({interpreter:j(e,!1,c,f),completion:Object.keys(e)})});else if("string"===g)xa.ignoreSystemDescribe?(e={interpreter:i(b,c)},a.isArray(xa.completion)&&(e.completion=xa.completion),d(e)):(ha.pause(),m(b,c,function(a){a?(h.interpreter=j(a,!1,c),h.completion=Object.keys(a)):h.interpreter=i(b,c),d(h),ha.resume()}));else if("object"===g)d({interpreter:j(b,xa.checkArity),completion:Object.keys(b)});else{if("undefined"===g)b=a.noop;else if("function"!==g)throw g+" is invalid interpreter value";d({interpreter:b,completion:xa.completion})}}function t(b,c){var d="boolean"===a.type(c)?"login":c;return function(c,e,f,g){ha.pause(),a.jrpc(b,d,[c,e],function(a){f(!a.error&&a.result?a.result:null),ha.resume()},l)}}function v(a){return"string"==typeof a?a:"string"==typeof a.fileName?a.fileName+": "+a.message:a.message}function w(b,c){a.isFunction(xa.exceptionHandler)?xa.exceptionHandler.call(ha,b):ha.exception(b,c)}function x(){var a;a=ia.prop?ia.prop("scrollHeight"):ia.attr("scrollHeight"),ia.scrollTop(a)}function y(b,c){try{if(a.isFunction(c))c(function(){});else if("string"!=typeof c){var d=b+" must be string or function";throw d}}catch(e){return w(e,b.toUpperCase()),!1}return!0}function z(b,c){xa.convertLinks&&(b=b.replace(K,"[[!;;]$1]").replace(J,"[[!;;]$1]"));var d,e,f=a.terminal.defaults.formatters;if(!c.raw){for(d=0;d<f.length;++d)try{if("function"==typeof f[d]){var g=f[d](b);"string"==typeof g&&(b=g)}}catch(h){alert("formatting error at formatters["+d+"]\n"+(h.stack?h.stack:h))}b=a.terminal.encode(b)}if(da.push(ea),!c.raw&&(b.l
|
||
|
</head>
|
||
|
<body></body>
|
||
|
</html>
|
||
|
<?php } ?>
|