openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 1138a3f1db019f5bea4074993135d0016e37df7a
parent 678e8d37bedfac5f38d1ae33354086e124c80ca2
Author: Jan Dankert <develop@jandankert.de>
Date:   Mon, 27 Jun 2022 00:40:42 +0200

New: Marker interface 'Scriptable', Proxy class for MQTT, help() method in Scripts.

Diffstat:
Mmodules/cms/generator/TemplateGenerator.class.php | 2++
Mmodules/cms/generator/ValueGenerator.class.php | 11++++++++---
Amodules/cms/generator/dsl/DslCms.class.php | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mmodules/cms/generator/dsl/DslConsole.class.php | 4++--
Dmodules/cms/generator/dsl/DslDate.class.php | 51---------------------------------------------------
Mmodules/cms/generator/dsl/DslElement.class.php | 8++------
Mmodules/cms/generator/dsl/DslHttp.class.php | 5+++--
Mmodules/cms/generator/dsl/DslJson.class.php | 4++--
Amodules/cms/generator/dsl/DslMqtt.class.php | 43+++++++++++++++++++++++++++++++++++++++++++
Mmodules/cms/generator/dsl/DslObject.class.php | 5++---
Mmodules/cms/generator/dsl/DslPageContext.class.php | 4++--
Mmodules/cms/generator/dsl/DslProject.class.php | 3++-
Dmodules/cms/generator/dsl/DslSystem.class.php | 72------------------------------------------------------------------------
Mmodules/cms/generator/dsl/DslTemplate.class.php | 9+++------
Mmodules/dsl/ast/DslFunctionCall.class.php | 9++-------
Mmodules/dsl/ast/DslProperty.class.php | 10++++++----
Mmodules/dsl/ast/DslVariable.class.php | 2+-
Amodules/dsl/context/BaseScriptableObject.class.php | 21+++++++++++++++++++++
Dmodules/dsl/context/DslFunction.class.php | 8--------
Dmodules/dsl/context/DslObject.class.php | 9---------
Amodules/dsl/context/Scriptable.class.php | 16++++++++++++++++
Mmodules/dsl/executor/DslInterpreter.class.php | 2++
Amodules/dsl/standard/Date.class.php | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/dsl/standard/Helper.class.php | 15+++++++++++++++
Mmodules/dsl/standard/Script.class.php | 17+++++++++++++++--
Mmodules/dsl/standard/StandardArray.class.php | 17++++++++++++++++-
Mmodules/dsl/standard/StandardDate.class.php | 45++++++++++++++++++++++++++++++++++++++++++++-
Mmodules/dsl/standard/StandardMath.class.php | 4+++-
Amodules/dsl/standard/System.class.php | 36++++++++++++++++++++++++++++++++++++
Mmodules/dsl/standard/Write.class.php | 6++----
Mmodules/util/Mqtt.class.php | 4+---
31 files changed, 364 insertions(+), 191 deletions(-)

diff --git a/modules/cms/generator/TemplateGenerator.class.php b/modules/cms/generator/TemplateGenerator.class.php @@ -5,6 +5,7 @@ namespace cms\generator; use cms\base\Configuration; +use cms\generator\dsl\DslCms; use cms\generator\dsl\DslConsole; use cms\generator\dsl\DslHttp; use cms\generator\dsl\DslJson; @@ -135,6 +136,7 @@ class TemplateGenerator $executor = new DslInterpreter( DslInterpreter::FLAG_THROW_ERROR ); $executor->addContext([ 'console' => new DslConsole(), + 'cms' => new DslCms(), 'http' => new DslHttp(), 'json' => new DslJson(), ]); diff --git a/modules/cms/generator/ValueGenerator.class.php b/modules/cms/generator/ValueGenerator.class.php @@ -8,10 +8,12 @@ use cms\base\Configuration; use cms\base\Configuration as C; use cms\base\DB; use cms\base\Startup; +use cms\generator\dsl\DslCms; use cms\generator\dsl\DslConsole; use cms\generator\dsl\DslDocument; use cms\generator\dsl\DslHttp; use cms\generator\dsl\DslJson; +use cms\generator\dsl\DslMqtt; use cms\generator\dsl\DslObject; use cms\generator\dsl\DslPage; use cms\generator\dsl\DslPageContext; @@ -30,6 +32,7 @@ use cms\model\PageContent; use cms\model\Project; use cms\model\Template; use cms\model\Value; +use dsl\context\BaseScriptableObject; use dsl\DslException; use dsl\executor\DslInterpreter; use logger\Logger; @@ -800,14 +803,15 @@ class ValueGenerator extends BaseGenerator $executor = new DslInterpreter(DslInterpreter::FLAG_THROW_ERROR ); $executor->addContext( [ 'console' => new DslConsole(), + 'cms' => new DslCms(), 'http' => new DslHttp(), 'json' => new DslJson(), 'page' => new DslObject( $page ), 'context' => new DslPageContext( $pageContext ), 'project' => new DslProject( $page->getProject() ), - 'Mqtt' => new class{ - public static function open( $url ) { - return new Mqtt( $url ); + 'Mqtt' => new class extends BaseScriptableObject { + public static function open( $url,$user,$password ) { + return new DslMqtt( $url,$user,$password ); } } , @@ -1191,6 +1195,7 @@ class ValueGenerator extends BaseGenerator 'context' => new DslPageContext( $this->context->pageContext ), 'project' => new DslProject( (new BaseObject($this->context->pageContext->objectId))->load()->getProject() ), 'console' => new DslConsole(), + 'cms' => new DslCms(), 'value' => $inhalt, 'http' => new DslHttp(), 'json' => new DslJson(), diff --git a/modules/cms/generator/dsl/DslCms.class.php b/modules/cms/generator/dsl/DslCms.class.php @@ -0,0 +1,49 @@ +<?php + +namespace cms\generator\dsl; + +use cms\base\Startup; +use dsl\context\BaseScriptableObject; + +class DslCms extends BaseScriptableObject +{ + /** + * application version + * @var string + */ + public $version; + + /** + * application name + * @var string + */ + public $name; + /** + * build date + * @var null + */ + public $build; + /** + * api version + * @var string + */ + public $api; + + public function __construct() + { + $this->version = Startup::VERSION; + $this->build = Startup::DATE; + $this->name = Startup::TITLE; + $this->api = Startup::API_LEVEL; + } + + + /** + * @param $name + * @return array|false|string + */ + public function env( $name ) { + + return getenv('CMS_SCRIPT_'.$name); + } +} +\ No newline at end of file diff --git a/modules/cms/generator/dsl/DslConsole.class.php b/modules/cms/generator/dsl/DslConsole.class.php @@ -2,7 +2,7 @@ namespace cms\generator\dsl; -use dsl\context\DslObject; +use dsl\context\BaseScriptableObject; use logger\Logger; /** @@ -12,7 +12,7 @@ use logger\Logger; * * @package cms\generator\dsl */ -class DslConsole implements DslObject +class DslConsole extends BaseScriptableObject { public function log( $text ) diff --git a/modules/cms/generator/dsl/DslDate.class.php b/modules/cms/generator/dsl/DslDate.class.php @@ -1,50 +0,0 @@ -<?php - -namespace cms\generator\dsl; - -use cms\model\Page; -use cms\model\Project; -use dsl\context\DslObject; - - -/** - * Date. - * - * Similar to the javascript Date object - */ -class DslDate implements DslObject -{ - private $time; - - /** - * @param integer $time unix timestamp - */ - public function __construct( $time = null ) - { - if ( $time = null ) - $time = time(); - - $this->time = $time; - } - - - public function getDate() { return date('d',$this->time); } - public function getDay() { return date('w',$this->time); } - public function getFullYear() { return date('Y',$this->time); } - public function getHours() { return date('H',$this->time); } - public function getMilliseconds() { return 0; } - public function getMinutes() { return date('i',$this->time); } - public function getMonth() { return date('m',$this->time); } - public function getSeconds() { return date('s',$this->time); } - public function getTime() { return $this->time * 1000; } - public function getTimezoneOffset() { return date('y',$this->time)/60;} - public function getUTCDate() { return date('d',$this->time);} - public function getUTCDay() { return date('w',$this->time);} - public function getUTCFullYear() { return date('Y',$this->time);} - public function getUTCHours() { return date('H',$this->time);} - public function getUTCMilliseconds() { return 0;} - public function getUTCMinutes() { return date('i',$this->time);} - public function getUTCMonth() { return date('m',$this->time);} - public function getUTCSeconds() { return date('s',$this->time);} - public function getYear() { return date('y',$this->time); } -} -\ No newline at end of file diff --git a/modules/cms/generator/dsl/DslElement.class.php b/modules/cms/generator/dsl/DslElement.class.php @@ -2,14 +2,10 @@ namespace cms\generator\dsl; -use cms\model\BaseObject; use cms\model\Element; -use cms\model\Folder; -use cms\model\Page; -use cms\model\Template; -use dsl\context\DslObject as DslContextObject; +use dsl\context\BaseScriptableObject; -class DslElement implements DslContextObject +class DslElement extends BaseScriptableObject { private $element; diff --git a/modules/cms/generator/dsl/DslHttp.class.php b/modules/cms/generator/dsl/DslHttp.class.php @@ -2,11 +2,12 @@ namespace cms\generator\dsl; -use dsl\context\DslObject; +use dsl\context\BaseScriptableObject; +use dsl\context\Scriptable; use util\Http; use util\json\JSON; -class DslHttp implements DslObject +class DslHttp extends BaseScriptableObject { public function get( $url ) { diff --git a/modules/cms/generator/dsl/DslJson.class.php b/modules/cms/generator/dsl/DslJson.class.php @@ -2,10 +2,10 @@ namespace cms\generator\dsl; -use dsl\context\DslObject; +use dsl\context\BaseScriptableObject; use util\json\JSON; -class DslJson implements DslObject +class DslJson extends BaseScriptableObject { public function parse( $text ) diff --git a/modules/cms/generator/dsl/DslMqtt.class.php b/modules/cms/generator/dsl/DslMqtt.class.php @@ -0,0 +1,42 @@ +<?php + +namespace cms\generator\dsl; + +use dsl\context\BaseScriptableObject; +use dsl\context\Scriptable; +use util\Http; +use util\json\JSON; +use util\Mqtt; + +/** + * A Proxy for MqTT methods. + */ +class DslMqtt extends BaseScriptableObject +{ + /** + * @var Mqtt + */ + private $mqtt; + + + public function __construct($url,$user,$password ) + { + $this->mqtt = new Mqtt( $url ); + $this->mqtt->connect( $user, $password ); + } + + public function publish($topic,$value) + { + $this->mqtt->publish($topic,$value); + } + + public function subscribe($topic) + { + return $this->mqtt->subscribe($topic); + } + + public function disconnect() + { + $this->mqtt->disconnect(); + } +} +\ No newline at end of file diff --git a/modules/cms/generator/dsl/DslObject.class.php b/modules/cms/generator/dsl/DslObject.class.php @@ -5,10 +5,9 @@ namespace cms\generator\dsl; use cms\model\BaseObject; use cms\model\Folder; use cms\model\Page; -use cms\model\Template; -use dsl\context\DslObject as DslContextObject; +use dsl\context\BaseScriptableObject; -class DslObject implements DslContextObject +class DslObject extends BaseScriptableObject { private $object; diff --git a/modules/cms/generator/dsl/DslPageContext.class.php b/modules/cms/generator/dsl/DslPageContext.class.php @@ -6,10 +6,10 @@ use cms\generator\PageContext; use cms\model\BaseObject; use cms\model\Language; use cms\model\Model; -use dsl\context\DslObject as DslContextObject; +use dsl\context\BaseScriptableObject; use dsl\DslRuntimeException; -class DslPageContext implements DslContextObject +class DslPageContext extends BaseScriptableObject { private $pageContext; diff --git a/modules/cms/generator/dsl/DslProject.class.php b/modules/cms/generator/dsl/DslProject.class.php @@ -4,8 +4,9 @@ namespace cms\generator\dsl; use cms\model\Folder; use cms\model\Project; +use dsl\context\BaseScriptableObject; -class DslProject implements \dsl\context\DslObject +class DslProject extends BaseScriptableObject { private $project; diff --git a/modules/cms/generator/dsl/DslSystem.class.php b/modules/cms/generator/dsl/DslSystem.class.php @@ -1,71 +0,0 @@ -<?php - -namespace cms\generator\dsl; - -use cms\base\Startup; -use dsl\context\DslObject; - -class DslSystem implements DslObject -{ - /** - * application version - * @var string - */ - public $version; - - /** - * application name - * @var string - */ - public $name; - /** - * build date - * @var null - */ - private $build; - /** - * api version - * @var string - */ - private $api; - /** - * runtime - * @var string - */ - private $runtime; - /** - * Operating system - * @var string - */ - private $os; - - public function __construct() - { - $this->version = Startup::VERSION; - $this->build = Startup::DATE; - $this->name = Startup::TITLE; - $this->api = Startup::API_LEVEL; - $this->runtime = PHP_VERSION; - $this->os = PHP_OS; - } - - - /** - * Gets the current date object. - * @return DslDate - */ - public function now() { - - return new DslDate(); - } - - - /** - * @param $name - * @return array|false|string - */ - public function env( $name ) { - - return getenv('CMS_DSL_'.$name); - } -} -\ No newline at end of file diff --git a/modules/cms/generator/dsl/DslTemplate.class.php b/modules/cms/generator/dsl/DslTemplate.class.php @@ -2,14 +2,11 @@ namespace cms\generator\dsl; -use cms\model\BaseObject; -use cms\model\Folder; -use cms\model\Page; use cms\model\Template; -use dsl\context\DslObject as DslContextObject; +use dsl\context\BaseScriptableObject; + +class DslTemplate extends BaseScriptableObject { -class DslTemplate implements DslContextObject -{ private $template; public $name; diff --git a/modules/dsl/ast/DslFunctionCall.class.php b/modules/dsl/ast/DslFunctionCall.class.php @@ -43,12 +43,7 @@ class DslFunctionCall implements DslStatement if ( ! is_array($parameterValues)) $parameterValues = array($parameterValues); - if ( $function instanceof \dsl\context\DslFunction ) { - // call "external" native function - - return call_user_func_array(array($function,'execute'),$parameterValues ); - } - elseif ( $function instanceof DslFunction ) { + if ( $function instanceof DslFunction ) { $parameters = $function->parameters; @@ -56,7 +51,7 @@ class DslFunctionCall implements DslStatement throw new DslRuntimeException('function call has '.sizeof($parameterValues).' parameters but the function has '.sizeof($parameters).' parameters'); // Put all function parameters to the function context. - $parameterContext = array_combine( $parameters, $parameterValues ); + $parameterContext = array_combine( $parameters, array_slice($parameterValues,0,sizeof($parameters)) ); $subContext = array_merge( $context,$parameterContext ); return $function->execute( $subContext ); diff --git a/modules/dsl/ast/DslProperty.class.php b/modules/dsl/ast/DslProperty.class.php @@ -3,6 +3,7 @@ namespace dsl\ast; use cms\generator\dsl\DslObject; +use dsl\context\Scriptable; use dsl\DslRuntimeException; class DslProperty implements DslStatement @@ -40,6 +41,11 @@ class DslProperty implements DslStatement // copy object methods to the object context to make them callable. foreach( get_class_methods( $object ) as $method ) { $objectContext[ $method ] = function() use ($method, $object) { + + // For Security: Do not expose all available objects, they must implement a marker interface. + if ( ! $object instanceof Scriptable ) + throw new DslRuntimeException('security: Object '.get_class($object).' is not scriptable and therefore not available in script context'); + return call_user_func_array( array($object,$method),func_get_args() ); }; } @@ -55,10 +61,6 @@ class DslProperty implements DslStatement $prop = $this->property->execute( $objectContext ); - // TODO: how to recognize objects - // For Security: Do not expose internal objects. - //if ( is_object($prop) && ! $prop instanceof DslObject ) - // $prop = '@'.get_class($prop).'@'; return $prop; } diff --git a/modules/dsl/ast/DslVariable.class.php b/modules/dsl/ast/DslVariable.class.php @@ -20,7 +20,7 @@ class DslVariable implements DslStatement public function execute( & $context ) { if ( ! array_key_exists( $this->name, $context ) ) - throw new DslRuntimeException('variable \''.$this->name.'\' does not exist.'); + throw new DslRuntimeException('\''.$this->name.'\' does not exist'); return $context[ $this->name ]; } diff --git a/modules/dsl/context/BaseScriptableObject.class.php b/modules/dsl/context/BaseScriptableObject.class.php @@ -0,0 +1,20 @@ +<?php + + +namespace dsl\context; + +use dsl\standard\Helper; + +class BaseScriptableObject implements Scriptable +{ + + public function __toString() + { + return "Script object"; + } + + public function help() + { + return Helper::getHelp($this); + } +} +\ No newline at end of file diff --git a/modules/dsl/context/DslFunction.class.php b/modules/dsl/context/DslFunction.class.php @@ -1,7 +0,0 @@ -<?php - -namespace dsl\context; - -interface DslFunction -{ -} -\ No newline at end of file diff --git a/modules/dsl/context/DslObject.class.php b/modules/dsl/context/DslObject.class.php @@ -1,8 +0,0 @@ -<?php - -namespace dsl\context; - -interface DslObject -{ - -} -\ No newline at end of file diff --git a/modules/dsl/context/Scriptable.class.php b/modules/dsl/context/Scriptable.class.php @@ -0,0 +1,15 @@ +<?php + +namespace dsl\context; + +/** + * Class is callable from scripts. + * + * Classes whose methods should be callable from user scripts must implement this interface. + * + * This is a marker interface which do not has methods by design. + * + * If a class do not implement this interface then its methods cannot be called out of a script. + * This is for security reasons: You cannot expose your classes to the user context by mistake. + */ +interface Scriptable {} +\ No newline at end of file diff --git a/modules/dsl/executor/DslInterpreter.class.php b/modules/dsl/executor/DslInterpreter.class.php @@ -9,6 +9,7 @@ use dsl\standard\Script; use dsl\standard\StandardArray; use dsl\standard\StandardDate; use dsl\standard\StandardMath; +use dsl\standard\System; use dsl\standard\Write; class DslInterpreter @@ -38,6 +39,7 @@ class DslInterpreter // Standard-Globals $this->addContext( [ + 'System'=> new System(), 'Math' => new StandardMath(), 'Array' => new StandardArray(), 'Date' => new StandardDate(), diff --git a/modules/dsl/standard/Date.class.php b/modules/dsl/standard/Date.class.php @@ -0,0 +1,62 @@ +<?php + +namespace dsl\standard; + +use dsl\context\BaseScriptableObject; + + +/** + * Date. + * + * Similar to the javascript Date object + */ +class Date extends BaseScriptableObject +{ + private $time; + + /** + * @param integer $time unix timestamp + */ + public function __construct( $time = null ) + { + if ( $time == null ) + $time = time(); + + $this->time = $time; + } + + + public function getDate() { return date('d',$this->time); } + public function getDay() { return date('w',$this->time); } + public function getFullYear() { return date('Y',$this->time); } + public function getHours() { return date('H',$this->time); } + public function getMilliseconds() { return 0; } + public function getMinutes() { return date('i',$this->time); } + public function getMonth() { return date('m',$this->time); } + public function getSeconds() { return date('s',$this->time); } + public function getTime() { return $this->time * 1000; } + public function getTimezoneOffset() { return date('y',$this->time)/60;} + public function getUTCDate() { return date('d',$this->time);} + public function getUTCDay() { return date('w',$this->time);} + public function getUTCFullYear() { return date('Y',$this->time);} + public function getUTCHours() { return date('H',$this->time);} + public function getUTCMilliseconds() { return 0;} + public function getUTCMinutes() { return date('i',$this->time);} + public function getUTCMonth() { return date('m',$this->time);} + public function getUTCSeconds() { return date('s',$this->time);} + public function getYear() { return date('y',$this->time); } + + public function __toString() + { + return date('r'); + } + + + /** + * @return string + */ + public function help() + { + return Helper::getHelp($this); + } +} +\ No newline at end of file diff --git a/modules/dsl/standard/Helper.class.php b/modules/dsl/standard/Helper.class.php @@ -0,0 +1,14 @@ +<?php + + +namespace dsl\standard; + + +class Helper +{ + public static function getHelp( $obj ) { + + return 'Object properties: '.implode(', ',array_map(function($property) { return ''.$property; },get_object_vars($obj))).';'. + ' methods: '.implode(', ',array_map(function($property) { return ''.$property.'()'; },get_class_methods($obj))); + } +} +\ No newline at end of file diff --git a/modules/dsl/standard/Script.class.php b/modules/dsl/standard/Script.class.php @@ -3,10 +3,10 @@ namespace dsl\standard; use dsl\ast\DslStatement; -use dsl\context\DslObject; +use dsl\context\BaseScriptableObject; use dsl\DslToken; -class Script implements DslObject +class Script extends BaseScriptableObject { /** * @var DslToken[] @@ -53,4 +53,17 @@ class Script implements DslObject { return print_r($this->ast,true); } + + public function __toString() + { + return "Script Info, call help() for help."; + } + + /** + * @return string + */ + public function help() + { + return Helper::getHelp($this); + } } \ No newline at end of file diff --git a/modules/dsl/standard/StandardArray.class.php b/modules/dsl/standard/StandardArray.class.php @@ -1,11 +1,26 @@ <?php namespace dsl\standard; -class StandardArray +use dsl\context\BaseScriptableObject; + +class StandardArray extends BaseScriptableObject { public function of() { return func_get_args(); } + + public function __toString() + { + return "Arrays:Object"; + } + + /** + * @return string + */ + public function help() + { + return Helper::getHelp($this); + } } \ No newline at end of file diff --git a/modules/dsl/standard/StandardDate.class.php b/modules/dsl/standard/StandardDate.class.php @@ -1,7 +1,9 @@ <?php namespace dsl\standard; -class StandardDate +use dsl\context\BaseScriptableObject; + +class StandardDate extends BaseScriptableObject { /** * Date.now() @@ -14,4 +16,45 @@ class StandardDate return time(); } + + + + /** + * Gets the current date object. + * @return Date + */ + public function getDate( $date = null ) { + + return new Date( $date ); + } + + + + /** + * Gets the current date object for a given date. + * @return Date + */ + public function getDateFor( $year = 0,$month = 0,$day = 0,$hour = 0,$minute = 0,$second = 0 ) { + + $month++; // month in JS is 0-based, but in PHP not. + + return new Date( mktime( $hour, $minute, $second, $month, $day, $year ) ); + } + + + public function __toString() + { + return "Arrays:Object"; + } + + public function help() + { + return Helper::getHelp($this); + } + + + public function parse( $dateAsString ) { + + return strtotime( $dateAsString ); + } } \ No newline at end of file diff --git a/modules/dsl/standard/StandardMath.class.php b/modules/dsl/standard/StandardMath.class.php @@ -1,7 +1,9 @@ <?php namespace dsl\standard; -class StandardMath +use dsl\context\BaseScriptableObject; + +class StandardMath extends BaseScriptableObject { public $E = M_EULER; public $PI = M_PI; diff --git a/modules/dsl/standard/System.class.php b/modules/dsl/standard/System.class.php @@ -0,0 +1,35 @@ +<?php + +namespace dsl\standard; + +use dsl\context\BaseScriptableObject; + +class System extends BaseScriptableObject +{ + /** + * runtime + * @var string + */ + public $version; + + /** + * Operating system + * @var string + */ + public $os; + + public function __construct() + { + $this->version = PHP_VERSION; + $this->os = PHP_OS; + } + + /** + * @param $name + * @return array|false|string + */ + public function env( $name ) { + + return getenv('SCRIPTBOX_'.$name); + } +} +\ No newline at end of file diff --git a/modules/dsl/standard/Write.class.php b/modules/dsl/standard/Write.class.php @@ -2,13 +2,11 @@ namespace dsl\standard; -use dsl\context\DslFunction; - -class Write implements DslFunction +class Write { public $buffer; - public function execute( $text ) + public function __invoke( $text ) { $this->buffer .= $text; } diff --git a/modules/util/Mqtt.class.php b/modules/util/Mqtt.class.php @@ -18,9 +18,7 @@ namespace util; -use cms\base\DB; use logger\Logger; -use withPraefixQuestionMark; /** * MQTT client. @@ -232,7 +230,7 @@ class Mqtt { } - public function readPacketFromServer() { + protected function readPacketFromServer() { if (!is_resource($this->connection)) throw new \Exception('Connection lost during transfer' );