EuroCMS Wiki page

AuthorVersionDate
Imri Paloja131-05-2022

This is the developer documentation for EuroCMS. As of yet there is no stable version of EuroCMS, as such this documentation is subject to change until the first stable version of EuroCMS is released.

The user documentation is yet to be written.

What is EuroCMS?

EuroCMS is a CMS, which stands for Content Management System. ECMS for short.

ECMS is a fully fledged alternative to other CMS systems, out of the box. So, at first install, you can start working without much hassle.

Nonetheless, It does provide a plugin system, for the specific modules, themes, and or widgets that you need.

Code wise, where possible, it tries to adhere to different coding standards: D.R.Y., MVC, PSR. The operative word being *tries*.

System Requirement

The current requirement for EuroCMS. Depending on future releases, the requirements listed below may change. Feel free to check back on this page.

Hardware requirement

In terms of memory and CPU, it all depends on how busy your web-server is going to be. If you have a website that has a few hundred visitors a month, a 1 core CPU and 1GiB ram, with 20G storage, *should* suffice.

But, if you have a high load website, with hundred of thousands of visitors a month, or more, it is highly recommended to monitor your server(s) resource usage, to see how much more resources you need to purchase.

Software requirement

RecommendedMinimumNotes
LinuxLatest Ubuntu LTS versionAlmaLinux/Rocky Linux.Any Linux distro that can provide the below listed software requirements and their dependencies *should* do the trick.
Web-serverNGINXApacheI tested ECMS most with NGINX. Although Apache should work also.
PHP8.0+8.0+See PHP requirement listed below.

Linux Requirement

namecomponentreason
exiftoollibrariesRead metadata of uploaded files; also strip the metadata of images for security purposes.
tridlibrariesFile validation during upload

PHP Requirement

List of PHP Modules needed by ECMS. This needs to be updated.

NameWho use thisHow is this going to be used?
browscapanalytics modulescrapping of user agent string, and save the data to a DB.
zlibcoreManagement of archive files
curlcoreFor the http client
opensslvarious components
sessioncoreManagement of Session
exifcorefallback if exiftool is not available.
jsoncoremanagement of json files
mysqlndcore
PDOcoreMangement of mariaDB
Pharcore
mysqlicore
pdo_mysqlcore
gdcoreManagement of image files.

Links

The EuroCMS Components

EuroCMS Components are things that extend the EuroCMS experience in a specific way.

  • Core: extend it's usage to other ECMS components

  • Libraries: extend it's usage to all modules

  • Modules: Extend its usage to ECMS users.

  • Themes & widgets: extend its usage to the front-end users.

  • Planner: can extend its usage to all other components

  • handlers: Can change the usage of some core components

The EuroCMS Engine

We provide an all encompassing Engine class, where it loads everything needed to start, and will also load the Content class, which loads the output needed depending on the requested URL.

There will be several constant in the engine, that will we used in various component of ECMS.

Engine also functions as a jailer. Every 'system' settings, variables and component is loaded from here. This to prevent none installed php files to access ECMS functions/classess/... without accessing it.

You can only loaded components from the class engine, and the class engine will check if you have the rights to access the requested functions.

Contemplate

Add a autoloader php function?

https://www.php.net/manual/en/language.oop5.autoload.php

As a replacement to __construct();?

Concept code:

spl_autoload_register(function ($class_name) {

	$file_name  ="$class_name.php"

	$path_to_file = Engine::ENGINE_CORE_DIR . "/$file_name";

	if(file_exists($path_to_file)) {
		include $class_name . '.php';
	} else {
		return false;
	}
});

$obj  = new Content();

Construct

When the class is constructed, it will check for the following

  • Direct access check.

It is not allowed to access the file directly: /engine/core/core.php. Everything in the URL is passed to the /index.php.

  • check_db - do we have a db connection?

If not, the Installer will be loaded, to generate the db credentials.

  • Handlers

The pre defined handlers will be loaded

  • Add core variables

These include the variables in $_SERVER as a constant.

This, makes is easier to request them, such as: $HTTP_HOST = constant('HTTP_HOST');.

  • add core function

The bare minimum functions needed to turn on the Engine.

  • Add Settings

The settings, such as handlers.

  • Includes

Such as the cache class, and the core functions.

  • Content

After that Themes and analytics will also be loaded.

The EuroCMS Content

  • domain

  • type

  • content

Wiki Pages of EuroCMS components

The EuroCMS Core

What are Cores?

These are things that resides in the ../eninge/core/ dir, and as such one is not able to uninstall them.

Any module and or widget can require them in their code.

Main characteristic

  • Cores are codes that are uninstallable

They are part of EuroCMS. As such, they cannot be uninstalled. Modules, widgets, themes can be uninstalled.

  • Can be used by any other ECMS component

A widget or module if allowed, is able to access the, for example uploads code.

During installation permissions must be granted. And or later on.

TODO

  • Write a package Manager

The EuroCMS Access/Audit logger?

The analytics module already logs every GET, POST,... request to the analytics table.

This Access Logger is mostly for code logging. Which code executed which code??

Think

  • Ponder on what you want to log that is not logged via the Analytics module.

  • Make this is an audit log?

Database table

Work in progress

access_iddomain_iduser_idgroup_idSESS_IDREMOTE_ADDRREAL_X_IPSERVER_PROTOCOLREQUEST_METHODstart_timeuser_agentbrowserbrowser_versionbrowser_typebrowser_bitsbrowser_makerrenderingengine_namerenderingengine_versionplatformplatform_versionplatform_bitsplatform_makerdevice_namedevice_type
11nullnull{PHP SESS ID}127.0.0.1{REAL_X_IP}HTTP/1.0GET{time}Firefox119.0Browser64Mozilla FoundationGecko119.0Ubuntu22.0464Canonical FoundationLinux DesktopDesktop
111{PHP SESS ID}127.0.0.1{REAL_X_IP}HTTP/2.0GET{time}
  • access_id: auto incremented numeric value

  • domain_id: The current domain id

  • user_id: The logged in user id. Can be null if no user is logged in.

  • SESS_ID: The PHP Session ID.

  • REMOTE_ADDR: The visitors IP address

  • REAL_X_IP: If behind a proxy this will be filled with the visitors IP

  • SERVER_PROTOCOL: The visitors http protocol: http/1.0,http/2.0

  • REQUEST_METHOD: GET, POST, DELETE,...

  • start_time: The moment the visitor accessed this site

  • user_agent: The visitors user agent.

  • browser_name: The browser name

  • browser_version: The browser version

  • browser_type: The browser type

  • browser_bits: The browser arch type: 32/64?

  • browser_maker: The browser maker

  • renderingengine_name: The browser rendering engine name

  • renderingengine_version: The browser rendering engine version

  • platform: The os the browser is running on: Ubuntu/Android/...

  • platform_version: The platform version: 22.04

  • platform_bits: The platform arch type

  • platform_maker: The created of the platform: Canonical Foundation

  • device_name: The name of the device: Linux Desktop

  • device_type: The type of device: Linux Desktop/Mobile Phone

Permissions

Ponder: This has no permissions. Everything is logged?

It's an access logger/audit log. It's a security breach if one could delete everything from it, but, some logs can be in the GiB+ of sizes. So, a delete permission is added, to give users the ability to delete logs based on the access_id. Access IDs are auto incremented, so the log entry will always show if something has been deleted.

namedescriptionvaluesvalue_descriptionvalue_formatvalue_example
access_deletedelete something in the access log$access_iddelete log entries depending on the access_id value.csv50,51,52,53,54,55
  1. https://browscap.org/ua-lookup

  2. https://www.whatismybrowser.com/


The EuroCMS Access Control List

AuthorVersion
Imri Paloja1

Domains and routes have these:

  • IP Protection?

  • pword?

Ponder on adding Account ACLS here?

Users group, roles, permission check via this? The Users module already handles this: https://projects.eurobytes.eu/projects/eurocms/wiki/users

Reference



The EuroCMS Core Ajax

The only way to handle ajax requests is via the EuroCMS Ajax Controller.

Security Checks

When someone make a GET request to the ajax path, it will check if the unique ID is in the header, and if that is a local GET. Meaning not from an external source.

  • local access only

  • Ajax only requests?

This should probably by default. No direct access from external servers.

  • Access Control check

The EuroEditor can also request the file upload box, when trying to upload an image file. At AJAX request to the upload box, make sure it does an ACL check. Just in case unauthorized users are requesting it...

  • Random generated path? So that a hacker does not know where to GET/POST?

DB Structure

ajax_iddomain_iduser_idgroup_idnamepathcomponent_typecomponent_namehttp_methodslocal_onlyuser_lockstatus
1111FileUpload/Files/FileUploadmoduleFilesGETtruenullenabled
2111Refresh/themes/W3schools/refreshthemesW3schoolsGET,POSTtruenullenabled

The EuroCMS Ajax Controller

Figure out where in the sub wiki pages to save this information.

The admin panel has JS code, that is used everyhere.

/**
 * This file is part of the EuroCMS project
 *
 * (c) Imri Paloja <imri.paloja@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

async function Ajax(DATA,HTTP_METHOD,PATH) {

	if (window.XMLHttpRequest) {
		// code for IE7+, Firefox, Chrome, Opera, Safari
		xmlhttp = new XMLHttpRequest();
	} else {
		// code for IE6, IE5
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	xmlhttp.onreadystatechange = function() {
		if (this.readyState === 4 && this.status === 200) {
			document.getElementById("notification-reponse").innerHTML = this.responseText;
			//						 ^ edit this
		}
	};


	await fetch(PATH, {
		method: HTTP_METHOD,
		body: DATA
	});
}

The EuroCMS Core Analytics component

This will use the get_browser(); php function with browscap data, for user agent information, and ipinfo.io for the IP information.

Provides way to get metrics regarding visitors and their browsers.

IPinfo.io and the user agent is parsed to provide detailed information, for developers and marketing alike.

GDPR Rules

  1. Audit Your Data for Personally Identifiable Information (PII)

  2. Turn on IP Anonymization.

  3. Audit your Collection of Pseudonymous Identifiers (hashed Emails, User IDs)

  4. Update your Privacy Policy.

  5. Build an Opt In/Out Capability.

IPinfo.io

ECMS use ipinfo.io for the retrieval of IP information.

"Free usage of our API is limited to 50,000 API requests per month. If you exceed that limit, we'll return a 429 HTTP status code to you." - ipinfo.io, developer, Rate Limits

The IP that makes the request is counted. If that IP address has made 50,000 requests, then that IP gets the 429 HTTP status code.

To round out those request, that comes to 1785.71+- per day. Most websites, are not close to 10,000 per month. For the high volume websites, we will also support the payed version of IPInfo.io.

Below is the data that the free version outputs. All of the below data are also available as a PHP constant. This is done to reduce the requests made to IP info.

  1. ipinfo_ip - Hide this from the developers? Privacy purposes?

  2. ipinfo_hostname

  3. ipinfo_city

  4. ipinfo_region

  5. ipinfo_country

  6. ipinfo_loc

  7. ipinfo_org

  8. ipinfo_postal

  9. ipinfo_timezone

  10. ipinfo_readme

keyvalue
IPIP ADRESS(Will be encrypted in the stable version)
hostnameThe reverse ip of the hostname
cityCity name
regionRegion
countryCountry short code
locAltitude, Longitude
orgISP
postalPostal code
timezoneEurope/Amsterdam
readmehttps://ipinfo.io/missingauth

The Full output json file

The paid plans provides the following data. The IP info used is from a google owned IP. google.com:

{
  "ip":"142.250.72.110",
  "hostname":"lga34s32-in-f14.1e100.net",
  "city":"New York City",
  "region":"New York",
  "country":"US",
  "loc":"40.7143,-74.0060",
  "org":"AS15169 Google LLC",
  "postal":"10004",
  "timezone":"America/New_York",
  "asn":{
    "asn":"AS15169",
    "name":"Google LLC",
    "domain":"google.com",
    "route":"142.250.0.0/15",
    "type":"business"
  },
  "company":{
    "name":"Google LLC",
    "domain":"google.com",
    "type":"business"
  },
  "privacy":{
    "vpn":false,
    "proxy":false,
    "tor":false,
    "relay":false,
    "hosting":false,
    "service":""
  },
  "abuse":{
    "address":"US, CA, Mountain View, 1600 Amphitheatre Parkway, 94043",
    "country":"US",
    "email":"network-abuse@google.com",
    "name":"Abuse",
    "network":"142.250.0.0/15",
    "phone":"+1-650-253-0000"
  },
  "domains":{
    "ip":"142.250.72.110",
    "total":4,
    "domains":[
      "bitechnologies.ng",
      "ratscraps.com",
      "raaatscraps.com",
      "raatscraps.com"
    ]
  }
}

browscap

Next to that, we also provide php constant of browscap variables: https://browscap.org/.

Please view http://browscap.org/ua-lookup for an example output of the data, and also check the wiki page, for detailed examples on the data https://github.com/browscap/browscap/wiki

You can use the ECMS function __ecms_UserAgent(). Which will put all the browscap data in a PHP constant, which you can use later on.

Note:

  1. Please read Browser detection using the user agent for when you want to use this feature.

  2. At the time of writing, whatismybrowser.com, states that there are 184.934.645 user agents. browscap does *not* have all of them listed.

Be aware of this when developing code around the assumption that browscap always provides data.

Example data:

KeyValue
parentFirefox 100.0
commentFirefox 100.0
browserFirefox
browser_typeBrowser
browser_bits64
browser_makerMozilla Foundation
browser_modusunknown
version100.0
majorver100
minorver0
platformUbuntu
platform_versionunknown
platform_descriptionUbuntu Linux
platform_bits64
platform_makerCanonical Foundation
alphafalse
betafalse
win16false
win32false
win64true
framestrue
iframestrue
tablestrue
cookiestrue
backgroundsoundsfalse
javascripttrue
vbscriptfalse
javaappletstrue
activexcontrolsfalse
ismobiledevicefalse
istabletfalse
issyndicationreaderfalse
crawlerfalse
isfakefalse
isanonymizedfalse
ismodifiedfalse
cssversion3
aolversion0
device_nameLinux Desktop
device_makerunknown
device_typeDesktop
device_pointing_methodmouse
device_code_nameLinux Desktop
device_brand_nameunknown
renderingengine_nameGecko
renderingengine_version100.0
renderingengine_descriptionFor Firefox, Camino, K-Meleon, SeaMonkey, Netscape, and other Gecko-based browsers.
renderingengine_makerMozilla Foundation

code

class analytics {

	function __construct() {
    	## do something at class start?
    	## dependency check?
    }

	public function get_browser() {}
	public function IPInfo() {}
	public function Save() {}

	function __desctruct() {
    	## do something after class finish.
    }
}

Reference

The EuroCMS API

Using REST API.

Generate an API key.

Settings

  • Generate API key
  • disable/enable features what this API key is allowed to use
  • reg_date?
  • expiration_date
  • GET requests limit?
  • IP block?
  • ...

Future features

  • xml output
  • yaml output?

Some basic yaml regex.

$print_r = print_r($_SERVER,true);

echo $print_r;

$match = preg_replace('/[ ]*\[/m', '', "$print_r");

echo preg_replace('/\] => /', ': ', "$match");

// https://3v4l.org/NEsVX
  • Custom output? Serialize and regex de PHP data array to an output that is needed.

We had XML, JSON and now yaml. In the future we could have a new output format. So, having an output creator, seems the best thing to do.

DB structures

api_iddomain_iduser_idgroup_iddescriptionunameapi_keypermission_idcreation_dateexp_daterequests_limitrequests_limit_perrequest_countauth_methodsip_denyip_allowpwordtimezonestatus
1111John's keyjohn{SHA512}1,2,3,4,5,6,7,8,9{creation_date}{exp_date}1000day123pword,api_keynull{CLIENT_IP}{BCRYPT}Europe/Amsterdamenabled
2238JNEnull{SHA512}1,2,3{creation_date}null100week25api_keynullnullnullnullenabled
2238BLDnull{SHA512}9,8,7,6,5{creation_date}nullnullnull54673567api_keyallCLIENT_IP{BCRYPT}Europe/Amsterdamdisabled
  • api_id: auto increment ID
  • domain_id: The domain ID of the domain that is currently being viewed.
  • user_id: The ID of the user that created this API key.
  • group_id: The ID of the group that has rights to this key.
  • description: The description of the API key.
  • uname: The username for this API key. Optional setting
  • api_key: The  - sha512sum - API key. This is used for authentication.
  • permission_id: All of the things this API has permission to.
  • creation_date: the registration date of the API key.
  • exp_date: When this API key will expire.
  • request_limit: The maximum amount of GET requests this api key is allowed to perform.
  • requests_limit_per: If set, the counter is reset per day/week/month.
  • request_count: The total amount of request this API has made.
  • auth_methods: How do you want users to authenticate using this key.
  • ip_deny: IP protect this API key. If this is set, this will block all other IPs instead of the ones specified.
  • ip_allow: Whitelist IPs. Only if the ip_deny is set, will this have any use.
  • pword: The password for this API key. Optional setting
  • timezone: Set the specific timezone for this key.
  • status: Set to enabled or expired, when the key is expired.

example json structure

{
  "api":{
    "headers":{
      "status":"HTTP/1.1 200 Connection established",
      "server":"nginx",
      "date":"Tue, 12 Apr 2022 06:45:32 GMT",
      "content-type":"text/html; charset=UTF-8",
      "expires":"Thu, 19 Nov 1981 08:52:00 GMT",
      "cache-control":"no-store, no-cache, must-revalidate",
      "pragma":"no-cache",
      "x-content-type-options":"nosniff",
      "x-frame-options":"SAMEORIGIN",
      "x-permitted-cross-domain-policies":"none",
      "referrer-policy":"no-referrer-when-downgrade",
      "strict-transport-security":"max-age=15768000",
      "access-control-allow-origin":"*",
      "x-xss-protection":"1; mode=block",
      "X-Firefox-Spdy":"h2"
    },
    "content":"The PHP data array here"
  }
}

Links

The EuroCMS Core Cache

The Core Cache can create a cached version of several types of files.

With EuroCMS cache, you can manage those cached files.

EuroCMS Caching

If there are no other Caching methods available for your server, you can use the builtin EuroCMS caching.

  • Check if the requested URI is cached

If a URL was requested, it will check if the URL is cached, if cached, it will "GET" the cached contents.

The cached file is not a full .html file. It's a collection of several cached files.

  • If cached: Load the cached uri
  • If not cached: generate the content for the requested URI (DB Query)

Opcache

The opcaching needs to be enabled in the PHP configuration file.

MariaDB Caching

The MariaDB Query Caching needs to be setup in the MariaDB configuration file

Further Reading

The EuroCMS Components

AuthorVersion
Imri Paloja1

EuroCMS Components are things that extend the EuroCMS experience in a specific way.

  • Core: extend it's usage to other ECMS components
  • Libraries: extend it's usage to all modules
  • Modules: Extend its usage to ECMS users.
  • Themes & widgets: extend its usage to the front-end users.
  • Planner: can extend its usage to all other components
  • handlers: Can change the usage of some core components

The EuroCMS Engine

We provide an all encompassing Engine class, where it loads everything needed to start, and will also load the Content class, which loads the output needed depending on the requested URL.

There will be several constant in the engine, that will we used in various component of ECMS.

Engine also functions as a jailer. Every 'system' settings, variables and component is loaded from here. This to prevent none installed php files to access ECMS functions/classess/... without accessing it.

You can only loaded components from the class engine, and the class engine will check if you have the rights to access the requested functions.

Contemplate

Add a autoloader php function?

https://www.php.net/manual/en/language.oop5.autoload.php

As a replacement to __construct();?

Concept code:

spl_autoload_register(function ($class_name) {

	$file_name  ="$class_name.php"

	$path_to_file = Engine::ENGINE_CORE_DIR . "/$file_name";

	if(file_exists($path_to_file)) {
		include $class_name . '.php';
	} else {
		return false;
	}
});

$obj  = new Content();

Construct

When the class is constructed, it will check for the following

  • Direct access check.

It is not allowed to access the file directly: /engine/core/core.php. Everything in the URL is passed to the /index.php.

  • check_db - do we have a db connection?

If not, the Installer will be loaded, to generate the db credentials.

  • Handlers

The pre defined handlers will be loaded

  • Add core variables

These include the variables in $_SERVER as a constant.

This, makes is easier to request them, such as: $HTTP_HOST = constant('HTTP_HOST');.

  • add core function

The bare minimum functions needed to turn on the Engine.

  • Add Settings

The settings, such as handlers.

  • Includes

Such as the cache class, and the core functions.

  • Content

After that Themes and analytics will also be loaded.

The EuroCMS Content

  • domain
  • type
  • content

Wiki Pages of EuroCMS components

The EuroCMS Core Cookies Code

This will fill up the EuroCMS cookies per HTTP_HOST

code

The code in short:

$cookie_name = constant('cookie_id');
$cookie_domain = constant('cookie_domain');
$cookie_expires = constant('cookie_expires');
$httpOnly = constant('httpOnly');
$path = constant('path');
$samesite = constant('samesite');
$secure = constant('secure');
$value = constant('value');

setcookie("$cookie_name", "$value", "$cookie_expires", "$path","$domain","$secure","$httponly");
# setcookie(name, value, expire, path, domain, secure, httponly);

The code in lenth:

class cookie {

	const name = '';
	const value = '';
	const expires_or_options = '';
	const path = '';
	const domain = '';
	const secure = '';
	const httponly = '';
	const options = '';

	public function set($cookie_name, $value, $cookie_expires, $path,$domain,$secure,$httponly) {
		setcookie("$cookie_name", "$value", "$cookie_expires", "$path","$domain","$secure","$httponly");			
	}
}

Reference

The EuroCMS Databases

AuthorVersionDate
Imri Paloja131-05-2022

The EuroCMS database structure

This is the default structure of the EuroCMS database tables.

{tablename}_iddomain_iduser_idgroup_id............user_lockstatus
1[0-9][0-9][0-9]1enabled
2[0-9][0-9][0-9]nulldisabled
3[0-9][0-9][0-9]nullenabled
  • {tablename}_id: [0-9] - required; auto increment, not empty

If the table name is Files with an S, plural, the ID name would be file_id, singular. If the table name is singular, content, the ID name should also be content_id.

  • domain_id: [0-9] - required

The ID of the domain that is currently being visited.

  • user_id: [0-9] - required

The ID of the user that created the row.

  • group_id: [0-9] - required

The ID of the group that has access to this row of data.

  • ...
  • Everything in between can be anything that the developer wants it to be.
  • ...
  • user_lock: [0-9] - required

This needs to exists, but doesn't have to be used.

IDs of users that are able to modify this data. When to many user are in the group that can edit the data, and you want to only allow certain users, you can use the user lock.

  • status: enabled/disabled - required

Disable or enable this row. You can add different type of status items in here.

Databases

For now the supported database software:

  • MariaDB (main)
  • SQLite (secondary)

For local/intranet type setup.

  • PostgreSQL (tertiary) - future work

Later on, if the users require it, other Database software may be supported.

All databases that could be supported are listed on the PHP website: https://www.php.net/manual/en/refs.database.vendors.php

MariaDB

MariaDB is the main supported DB software.

SQLite

The SQLite database is the second supported db software.

Links

  1. https://www.php.net/manual/en/sqlite3.query.php
  2. https://www.php.net/manual/en/book.sqlite3.php

The Domains Core code

Check if the requested domain is available in our system.

The EuroCMS Errors

EuroCMS uses a custom error handler. Which it saves in the DB, for later viewing. Also use the notification module to display message to the user.

Implement something similiar in ECMS:

<?php
// Send notification through the server log if we can not
// connect to the database.
if (!Ora_Logon($username, $password)) {
    error_log("Oracle database not available!", 0);
}

// Notify administrator by email if we run out of FOO
if (!($foo = allocate_new_foo())) {
    error_log("Big trouble, we're all out of FOOs!", 1,
               "operator@example.com");
}

// another way to call error_log():
error_log("You messed up!", 3, "/var/tmp/my-errors.log");
?>

Reference

The EuroCMS Core functions

Make PHPStorm know custom php functions: read https://www.jetbrains.com/help/phpstorm/symfony-creating-helper-functions.html#method-parameter

These are the core functions that are readily available for your usage.

__ecms_BlockChar()

In the url bar, only alpha numeric value are allowed and nothing else.

This function checks if the url bar has blocked charachters in it.

function __ecms_BlockChar($url) {
	$value = preg_replace('/[a-zA-Z0-9\/\-]/', '', $url);
	if(empty($value)) {
		return false
	} else {
		return true;		
	}
}

Usage

if(__ecms_BlockChar()) {
	die('Block chars detected.');
}

__ecms_dump($dump);

A pretty output of var_dump, using the html tag <pre> ... </pre>

Code

/**
* var dump array
*
* @param $array variable Dumps information about a variable
* 
*/
function __ecms_dump($array) {
    echo "<pre>" . var_dump("$array"); . "</pre>";
}

Usage

__ecms_dump($array);

__ecms_GLOBALS($TYPE,$Value)

Pretty <table> ... </table> output of the $GLOBALS.

  • _GET
  • _POST
  • _COOKIE
  • _FILES
  • argv
  • argc
  • _SERVER

$GLOBALS — References all variables available in global scope.

An associative array containing references to all variables which are currently defined in the global scope of the script.

The variable names are the keys of the array.

Code:

__ecms_GLOBALS("$FROM","$VALUE") {
     return filter_input($FROM, "$VALUE", FILTER_SANITIZE_STRING);
}

Usage:

echo __ecms_GLOBALS("SERVER","REMOTE_ADDR");

__ecms_MiniCSS($css)

Minify css content

Code

function __ecms_MiniCSS($CSS) {
    // Remove comments
    $CSS = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $CSS);

    // Remove space after colons
    $CSS = str_replace(': ', ':', $CSS);

    // Remove whitespace
    $CSS = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $CSS);
    return $CSS;
}

Usage

echo __ecms_MiniCSS($CSS);

__ecms_MiniJS($JavaScript)

Minify js content

Code

function __ecms_MiniJS($JavaScript) {
    $blocks = array('for', 'while', 'if', 'else');
    $javascript = preg_replace('/([-\+])\s+\+([^\s;]*)/', '$1 (+$2)', $javascript);

    $pattern = '/(?:(?:\/\*(?:[^*]|(?:\*+[^*\/]))*\*+\/)|(?:(?<!\:|\\\|\')\/\/.*))/';
    $javascript = preg_replace($pattern, '', $javascript);


    // remove new line in statements
    $javascript = preg_replace('/\s+\|\|\s+/', ' || ', $javascript);
    $javascript = preg_replace('/\s+\&\&\s+/', ' && ', $javascript);
    $javascript = preg_replace('/\s*([=+-\/\*:?])\s*/', '$1 ', $javascript);

    // handle missing brackets {}
    foreach ($blocks as $block){
        $javascript = preg_replace('/(\s*\b' . $block . '\b[^{\n]*)\n([^{\n]+)\n/i', '$1{$2}', $javascript);
    }

    // handle spaces
    $javascript = preg_replace(array("/\s*\n\s*/", "/\h+/"), array("\n", " "), $javascript); // \h+ horizontal white space
    $javascript = preg_replace(array('/([^a-z0-9\_])\h+/i', '/\h+([^a-z0-9\$\_])/i'), '$1', $javascript);
    $javascript = preg_replace('/\n?([[;{(\.+-\/\*:?&|])\n?/', '$1', $javascript);
    $javascript = preg_replace('/\n?([})\]])/', '$1', $javascript);
    $javascript = str_replace("\nelse", "else", $javascript);
    $javascript = preg_replace("/([^}])\n/", "$1;", $javascript);
    //$javascript = preg_replace("/;?\n/", ";", $javascript);
    return $javascript;
}

usage

echo __ecms_MiniJS($JavaScripts);

__ecms_GetClientIP

Get the visitor IP and such.

Code

function __ecms_GetClientIP(){

    if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)){

        return  $_SERVER["HTTP_X_FORWARDED_FOR"];

    }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {

        return $_SERVER["REMOTE_ADDR"];

    }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {

        return $_SERVER["HTTP_CLIENT_IP"];
    }

    return '';
}

usage

echo __ecms_GetClientIP();

__ecms_IPInfo($IP)

Get IP information about the visitor.

__ecms_CronCheck()

Check if the code is being excecuted via cron.

Code

// Checks if you are being executed via cron
function __ecms_CronCheck() {

    // Lets see if our predefined constant exists
    if (defined('PHP_SAPI')) {

        $sapi_type = constant('PHP_SAPI');

    } else {

        $sapi_type = php_sapi_name();

    }

    if (preg_match('/cli/i', $sapi_type)) {

        return true;

    }

}

Usage

__ecms_HTMLENT($HTML)

Return only the html entity

Code

/**
* Convert all applicable characters to HTML entities
*
* @param $HMTL string string of HTML entities
* 
*/
__ecms_HTMLENT($HTML) {
	return htmlentities($HTML, ENT_QUOTES);	
}

Usage

echo __ecms_HTMLENT($HTML);

__ecms_IsBinary($content)

Check if the content given is a binary file

__ecms_BotCheck()

Checks if the current user agent is a bot

Code

function __ecms_BotCheck() {
    // Checking if the current HTTP_USER_AGENT is a bot
    $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT'];
    if (preg_match('/bot|spider/i', $HTTP_USER_AGENT)) {
        // This is a bot
        return true;
    } else {
        return false;
    }
}

usage

if(__ecms_BotCheck()) {
	die('You are not allowed here...');
}

__ecms_UserAgent()

Put the browscap data in a variable. (Or just return the array?)

code

function __ecms_UserAgent() {
	return get_browser(null, true);
//	$browser = get_browser(null, true);
//	foreach($browser as $key => $value) {
//		define("browscap_$key", "$value");    
//		browscap_parent Firefox 0.9
//	}
}

usage

__ecms_UserAgent()

__ecms_Users()

Get user display name.

  • Make a class out of this?
  • Figure out the security implications with this
  • Make this only available for modules?
  • Create an admin namespace?

code

# Test this.
function __ecms_Users($IDs) {
	return DataBase::Query("SELECT dname,profile_pic from users WHERE user_id IN ($IDs);");
}

usage

__ecms_Users()

The EuroCMS Handlers

A handler is a specific task, that can be handled by multiple type of code.

db table

The DataBase table structure

handler_iddomain_iduser_idgroup_idcomponent_typecomponent_namenamehandlerdescriptionuser_lockstatus
1111corehandlersSecretsSQLiteSecrets are saved in SQLite1active
1111corehandlersSessionFileSessions are saved by the File handler9active
1111corehandlersDataBaseMariaDBDataBase is managed by MariaDB2active
1111corehandlersCommentDataBaseComments are handled by the default DataBase handler2active
1111corehandlershttpcURLhttp request are handled by cURL2active
1111corehandlersaccessMariaDBAccess Logs are specifically saved in MariaDB44active
1111corehandlerserrorMariaDBError Logs are specifically saved in MariaDB4active
1111corehandlersPHP{PHP_VERSION}The PHP handler is loaded based by the PHP_VERSION constant. e.g.: PHP.handler.8.0.php44active
1111corehandlerscachelocalThe local cache is handled locally.15active
1111corehandlersauthMariaDBThe user authentication is done by users that are saved in MariaDB.16active
1111corehandlersSearchDataBaseThe Search engine will search for things in the default DataBase17active
1111corehandlersNotificationsDataBaseThe notification handlers17active
1111modulesFilesStoragelocalWhere to store the uploaded files. Available options: WebDAV, AWS S3, Google Storage.4active

Ponder

  • Add a Roles and Permission handler to have the ability to load Roles and Permissions from different sources.
  • Add the same ability for modules. Modules then can also register handlers...

Permissions

namedescriptionvaluevalue description
handler_registerAdd a new handlerstring $name, string $handler, string $descriptionThe handler information
handler_removeRemove an existing handlerstring $handler_idThe handler ID
handler_modifyModify an existing handlerstring $handler_id, string $name, string $handler, string $descriptionThe handler ID and information
handler_user_locklock a handler from being modified by other usersstring $handler_idThe handler ID

The EuroCMS Core header component

This allows you to manage headers sent per HTTP_HOST.

Only owner(admins) are allowed to use this module. You can

Header validation?

It has happened before that an exploitation had succeeded via header?

Create regex?

  • HTST: ^Strict-Transport-Security: (max-age=[0-9]*;) (includeSubDomains;) (preload)

https://flaviocopes.com/http-request-headers/

https://en.wikipedia.org/wiki/List_of_HTTP_header_fields

Example of response headers

GET /path/to/page/ HTTP/2
Host: owasp.org
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://www.google.com/
Connection: keep-alive
Cookie: banner-seen=true
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
Pragma: no-cache
Cache-Control: no-cache
TE: trailers

db structure

header_iddomain_iduser_idgroup_idnameshort_descriptionvalues
HTTP Strict Transport Security
X-Frame-Options
X-Content-Type-Options
Content-Security-Policy
X-Permitted-Cross-Domain-Policies
Referrer-Policy
Clear-Site-Data
Cross-Origin-Embedder-Policy
Cross-Origin-Opener-Policy
Cross-Origin-Resource-Policy
Cache-Control

Permissions

There are a list of permission you can add to this user.

namedescription
header_addThe ability to add headers per domain
header_removeThe ability to remove headers per domain
header_modifyThe ability to modify headers per domain

db structure

header_iddomain_iduser_idgroup_idnamevaluesdescriptionuser_lockstatus
111Content-Security-Policydefault-src 'self'; img-src 'self' https: https://i.imgur.com; object-src 'none'Content Security Policy (CSP) is an HTTP header that allows site operators fine-grained control over where resources on their site can be loaded fromenabled
211Strict-Transport-Securitymax-age={number},includeSubDomainsHTTP Strict Transport Security (HSTS) is an HTTP header that notifies user agents to only connect to a given site over HTTPS, even if the scheme chosen was HTTPenabled

values in json example

{
  "values":{
    "max-age=":{
      "input":"number",
      "description":"The time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS."
    },
    "includeSubDomains":"If this optional parameter is specified, this rule applies to all of the site’s subdomains as well."
  }
}

Full Example json structure

{
  "Strict-Transport-Security":{
    "description":"Declare that a website is only accessible over a secure connection (HTTPS).",
    "values":{
      "max-age=":{
        "input":"number",
        "description":"The time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS."
      },
      "includeSubDomains":"If this optional parameter is specified, this rule applies to all of the site’s subdomains as well."
    }
  },
  "X-Frame-Options":{
    "description":"An HTTP header which indicates whether the browser should allow the webpage to be displayed in a frame within another webpage. Used as a defense against clickjacking attacks.",
    "values":{
      "deny":{
        "type":"text",
        "description":"No rendering within a frame."
      },
      "sameorigin":{
        "type":"text",
        "description":"No rendering if origin mismatch."
      }
    }
  },
  "X-Content-Type-Options":{
    "description":"Setting this header will prevent the browser from interpreting files as a different MIME type to what is specified in the Content-Type HTTP header (e.g. treating text/plain as text/css).",
    "values":{
      "nosniff":{
        "type":"text",
        "description":"Will prevent the browser from MIME-sniffing a response away from the declared content-type."
      }
    }
  }
}

Reference

The EuroCMS Login Controller

authordatestatus
Imri Paloja11-2023acceptance

Manages logins. This will also be used to view who has logged in, instead of the previous $_SESSION["USER_ID"].

DataBase table

Ponder:

  • group_id: Log the entire group into something??
  • uname: no need to query the uname in the users table?
  • $_SESSION: Save all this information in session? The new one is going to be private and optionally encrypted. And DataBase as storage(MariaDB/Redis/SQLite)
login_iddomain_iduser_idlogin_start_timelogin_end_timeipsess_idauth_method_usedlogin_tokenpermissionsstatus
111microtime(true)127.0.0.1{PHP SESS ID}ldapECMS-{-SHA512SUM-}1,2,3,4,5,6active
224microtime(true)127.0.0.1{PHP SESS ID}creds,email,telegramECMS-{-SHA512SUM-}1,2,3,4,5processing
3254microtime(true)127.0.0.1{PHP SESS ID}creds,emailECMS-{-SHA512SUM-}1,2,3,4inactive
4135microtime(true)microtime(true)127.0.0.1{PHP SESS ID}creds,telegramECMS-{-SHA512SUM-}1,2,3expired
512microtime(true)microtime(true)127.0.0.1{PHP SESS ID}credsECMS-{-SHA512SUM-}1,2terminated
616microtime(true)microtime(true)127.0.0.1{PHP SESS ID}creds,email,pwordECMS-{-SHA512SUM-}1concluded
  • login_id: auto incremented, there will be no dual logged in IDs
  • domain_id: The users logged in to the current domain
  • user_id: The user id of the currently logged in user.
  • date: The logged in date. If the session log in time is 30 minutes, this will be used as a basis.
  • IP: The logged in users IP.
  • sess_id: The PHP Session ID.
  • auth_method_used: The authentication method used: LDAP,creds,email,...
  • login_token: The sha512 login token. The content of the following columns is used as it's value: domain_id,user_id,date,ip,sess_id,auth_method_used,permissions,status.. Example output is ECMS-ABC12-ABC12-ABC12-ABC12-...-....
  • permissions: The logged in users loaded permissions
  • status: The status of the logged in user

Permissions

The feature login_add is hard-coded in the login controller, as it's the only controller that should be able to start the logged in process.

No delete and or modify features are present. For security purposes, so that people will always know who logged in at what time.

All of these features are domain aware! meaning everything is saved in the current domain.

namedescriptionvaluevalue descriptionvalue example
login_listList all of the logged in users (In the current domain, and within its own change of command)nullNo value needed. It will list all of the logins in the current domainnull
login_add (ponder this)Add a new user in the login process.int $domain_id, int $user_id, int $date,string $ip, string $sess_id, string $auth_method_used, string$login_token, string $permissions, string $status
login_set_statusSet the status of the user in the login process. Available options are: active,processing,inactive,expired,terminated,concluded
login_get_statusGet the status of the currently logged user.

login_list

name
data type
custom filtering

login_add

name$domain_id$user_id$date$ip$sess_id$auth_method_used$login_token$permissions$status
data typeintintstringstring(valid IP)stringstringstringstringstring
custom filteringnonenoneNumeric value with a dot.validate_ipalpha numeric valuecsv output.custom ECMS validatorcsvone of: active, processing, inactive, expired, terminated, concluded

login_set_status

name$status
data typestring
custom filteringString needs to be one of: active, processing, inactive, expired, terminated, concluded
expected value
expected valuedescription
activeThe user logged in successfully
processingThe user hasn't yet passed all of the validation methods
inactiveThe user hasn't been active in X amount of minutes.
expiredThe user was inactive and it passed the session expiration time.
terminatedThe user's session was terminated by someone with login_set_status privileges.
concludedThe user has logged himself out.
  • active: The user logged in successfully
  • processing: The user hasn't yet passed all of the validation methods
  • inactive: The user hasn't been active in X amount of minutes.
  • expired: The user was inactive and it passed the session expiration time.
  • terminated: The user's session was terminated by someone with login_set_status privileges.
  • concluded: The user has logged himself out.

login_get_status

name$status
data typestring
custom filteringString needs to be one of: active, processing, inactive, expired, terminated, concluded

The EuroCMS Core Mail

This core code will allow to send e-mails via a specific way.

This also accepts templates.

Table structure

mail_iddomain_iduser_idgroup_idtosend_datefromsubjectmessageadditional_headersstatustemplateuser_lockstatus
1111imri@eurobytes.euTest MessageLONGTEXTReply-toEBS

https://www.iana.org/assignments/message-headers/message-headers.xhtml

https://en.wikipedia.org/wiki/Email#Message_header

The EuroCMS Metrics

This will allow monitoring tools to query ECMS metrics

  1. Register an URL with the Routes module
  2. Let core.metrics.php handle it.
  3. Include and load the queries

When registering a module with metrics, have the component type and name, which creates the path to the metrics

The OpenMetrics will be used, to generate the output

UTF-8 MUST be used. Byte order markers (BOMs) MUST NOT be used. As an important reminder for implementers, byte 0 is valid UTF-8 while, for example, byte 255 is not.

The content type MUST be: application/openmetrics-text; version=1.0.0; charset=utf-8

Line endings MUST be signalled with line feed (\n) and MUST NOT contain carriage returns (\r). Expositions MUST end with EOF and SHOULD end with 'EOF\n'. - https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#overall-structure

Example output

# The Core EuroCMS metrics

ecms_core_total: 12
ecms_libraries_total: 34
ecms_modules_total: 56
ecms_themes_total: 78
ecms_widgets_total: 90

# The Modules EuroCMS metrics

# Users
ecms_modules_Users_total: 50
ecms_modules_Users_activated: 25
ecms_modules_Users_registered: 50
ecms_modules_Users_inactivated: 25

# Files
ecms_modules_Files_total: 50
ecms_modules_Files_image_png: 25
ecms_modules_Files_image_png: 25

# Domains
ecms_modules_Domains_website: 2
ecms_modules_Domains_total: 5
ecms_modules_Domains_redirect: 2
ecms_modules_Domains_module: 2

# Analytics
ecms_modules_analytics_browsers_firefox: 2
ecms_modules_analytics_unique_visitors: 2

Links

The EuroCMS Notification

View and manage notifications

Notifications db table

notification_iddomain_iduser_idgroup_idcomponentnameseveritytitlecontentviewed
111nullthemesSkeletonCRITICALMissing file (test.xml)long textno
211nullPHP? Engine?Engine:URLSecuritySQL injection attempt by PHPSESSID: ABCDEFGlong textno
311nullanalyticsNotFoundINFOA visitor generated a 404ong textno
411nullcoreUpdatesWarning5 updates are availablelong textno

code

class mail {


	public static function Send()


}

The EuroCMS Package Manager

When needing to install, remove, update packages from wherever.

Think about

  • Writing my own package format?

.tar.xz renamed to .ecms? Same as zip being used to rename to anything? doc,docx.

  • keep using tar balls?

Example .ecms Folder Structure

Might change in the future

  • Files.EuroCMS.v0.0.2.ecms
    • Files/
      • controller/
        • Files.mod.php
        • Files.dashboards.php
      • css/
        • Files.cont.css
        • Files.dashboards.css
      • files/
        • Files.cont.sql
      • docs/
        • SAVING.md
        • DELETING.md
      • js/
        • Files.cont.js
        • Files.bottom.cont.js
      • tmpl/
        • Files.cont.tmpl.php
      • handlers/
        • Files.storage.handlers.php
      • metadata.json
      • permissions.json
      • dependencies.json
      • Files.sha512sum

Notes

Things to remember when writing a package manager?

  • File validation?

gpg,ssdeep,sha[0-9]{1,3}sum

https://gnupg.org/download/integrity_check.html

https://www.gnupg.org/gph/en/manual/x135.html

https://www.devdungeon.com/content/how-verify-gpg-signature

  • hashed file values

Package json file

Embed this in the package manager file? Create a custom shebang? ?ECMS.

For example use the deb package information:

Package: nginx
Version: 1.20.2-1~jammy
Architecture: amd64
Maintainer: NGINX Packaging <nginx-packaging@f5.com>
Installed-Size: 3146
Depends: libc6 (>= 2.34), libcrypt1 (>= 1:4.1.0), libpcre3, libssl3 (>= 3.0.0~~alpha1), zlib1g (>= 1:1.1.4), lsb-base (>= 3.0-6), adduser
Conflicts: nginx-common, nginx-core
Replaces: nginx-common, nginx-core
Provides: httpd, nginx, nginx-r1.20.2
Filename: pool/nginx/n/nginx/nginx_1.20.2-1~jammy_amd64.deb
Size: 991196
MD5sum: 366c0c7cb8faf713d1a29bae919f0e50
SHA1: ed1f1b0f1cfa2e6c8e7d63892d2932c3295342c9
SHA256: 870fd7e7b04f133de034d0a76fce3fe156a207b59504f80fcadfe4d51d8dbbe7
Section: httpd
Priority: optional
Homepage: https://nginx.org
Description: high performance web server nginx [engine x] is an HTTP and reverse proxy server, as well as a mail proxy server.

These json are still work in progress.

SLIM

Removing the update link etc... The repo software should have all the necessary information.

Needed key in the json

  • ecms.version - [0-9.]

For our own repo, this is not necesary. But for when we have the repo plugin, customers have not updated it, their package json file might still contain removed,renamed keys.

It would be needed to see which package version they are using, so that the required keys can be parsed in the correct way.

  • app.name: [a-zA-Z] Obviously this would be needed.

  • app.version [0-9.]

To display the version of the package

  • app.channel: pre-alpha,alpha,beta,stable

For when the ECMS developers has a different

{
  "ecms":{
    "version":"0.0.1"
  },
  "package":{
    "name":"trid",
    "version":"0.2.1",
    "channel":"stable",
    "maintainer":"Imri Paloja <imri@packages.eurocms.eu>",
    "installed-Size":"145",
    "homepage":"https://packages.eurocms.eu/libraries/trid",
    "depends":null,
    "conflicts":null,
    "breaks":null,
    "replaces":null,
  },
  "app":{
    "author":"Marco Pontello <marcopon@nospam@gmail.com>",
    "version":null,
    "homepage":"https://mark0.net/soft-trid-e.html",
    "description":"File Identifier",
    "component":"library",
  }
}

changes.json

List of changes instead of a changes.md

{
  "Files":{
    "name":"Files - Mosiac release",
	"author": "Imri Paloja <imri@eurobytes.eu>"
    "release_date":"",
    "version_release":"1.2.3",
    "description":"htmlentities($desc,true)",
    "changes":{
      "update":{
        "jquery":"1.13.1"
      },
      "remove":{
        "normalize.css":""
      },
      "fix":{
        "bux":"Files not being uploaded"
      },
      "add":{
        "add":{
          "skeleton":"1.2.3"
        }
      },
      "change":{
        "browscap":"Not starting it up during runtime. Users can load it when necessary."
      },
      "breaking":{
        "core":{
          "renamed":"$FullUri variables to FULL_URI php constant",
          "removed":"the $Loggedin boolean variable."
        },
        "modules":{
          "files":{
            "renamed":"UploadFile() function to Upload()",
            "removed":"the $Loggedin boolean variable.",
            "update":"Updated Function Test1() to Test2"
          }
        }
      }
    }
  }
}

Full

{
  "ecms":{
    "version":"0.0.1",
    "data":{
      "author":"Imri Paloja <imri@eurobytes.eu>",
      "package":"Files",
      "version":"1.0.1",
      "component":"modules",
      "docs":"docs/ - figure how to do this",
      "organization":{
        "name":"EuroBytes",
        "chamber_of_commerce_number":"1234567890",
        "address":{
          "country":"Linux",
          "state_province":"Debian",
          "city":"Ubuntu",
          "zip_code":"2204 JJ",
          "street":"Localhost 127"
        },
        "opening_hours":{
          "Monday":"09:00,17:00",
          "Tuesday":"09:00,17:00",
          "Wednesday":"09:00,17:00",
          "Thursday":"09:00,17:00",
          "Friday":"09:00,17:00",
          "Saturday":null,
          "Sunday":null
        },
        "phone_number":"+00 (0) 12 - 345 67 89",
        "timezone":"Europe/Amsterdam",
        "email":"support+modules+files@packages.eurocms.eu"
      },
      "homepage":"https://packages.eurocms.eu/modules/Files",
      "description":"The EuroCMS Files Module allows you to manage different types of files.",
      "maintainers":{
        "current":"John Doe <john.doe@packages.eurocms.eu>",
      },
      "Installed-Size":"1024",
      "dependencies":{
        "components":{
          "libraries":{
            "exiftool":"=>0.0.1",
            "trid":"=>0.0.1"
          }
        },
        "php":{
          "imagick":{
            "version":"7.4",
            "requirement_level":"hard"
          },
          "php-exif":{
            "version":"7.4",
            "requirement_level":"hard"
          }
        }
      },
      "Provides":{
        "features":{
          "files_add":"The ability to upload files",
          "files_remove":"The ability to remove files"
        },
        "ajax":{
          "RefreshAjax":"Refresh page via ajax"
        },
        "planner":{
          "Refresh":"Refresh something"
        },
        "dashboards":{
          "view":"View Files From the dashboard"
        }
      },
      "update":{
        "version_location":{
          "GET":"https://packages.eurocms.eu/modules/Files/latest_version.txt",
          "dns":"modules.Files.packages.eurocms.eu"
        },
        "download":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.ecms",
        "changelog":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.txt",
        "validation":{
          "md5sum":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.ecms.md5sum",
          "sha1sum":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.ecms.sha1sum",
          "sha512sum":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.ecms.sha512sum",
          "gpg":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.ecms.gpg"
        },
        "license":{
          "GET":"https://packages.eurocms.eu/modules/Files/VERSION/Files-VERSION.license",
          "accept_license":true
        }
      },
      "permissions":{
        "components":{
          "core":{
            "uploads":{
              "execute":"Need the core Uploads component to upload files."
            },
            "database":{
              "files":"Need to have access to the files database table, for storing of files metadata and such."
            }
          },
          "modules":{
            "users":{

            }
          },
          "widgets":{
            "NavMenu":{

            }
          },
          "libraries":{
            "exiftool":{
              "read":"By default you get access to the main features, reading of metadata in exiftools case.",
              "validate":"To validate files",
              "thumbnail":"To extract thumbnails from files."
            },
            "trid":"read"
          }
        },
        "php":{
          "cURL":{
            "read":"Contemplate on this one??"
          }
        }
      }
    }
  }
}

Reference

The EuroCMS Permissions

The ECMS permissions are things that you can block access to per user, domain, ...

Core.Permissions

The main permissions file, is the core.permissions.php

functions list:

  • register - register a permission (It will save it in the DataBase)

  • GET - get the registered function

The logged-in user will be checked if it can access the requested permission.

  • check - Check if the user has rights to the registered function

  • list - list Registered functions

  • remove - remove the registered function

example:

GET a registered function.

$permissions = new permissions();
$files_add = $permissions->GET('files_add');

$files_add will have the requested permission content

e.g.: <button name="files_add" type="submit" value="Upload Files" onclick="upload()">

{Files,Users,Forms}.Permissions

If the checks in core.Permissions.php have passed, it will request the content from the Files permission controller.

files_add

DataBase

This will be used to request the wanted permission (e.g.: files_add,users_add,themes_add, ..., ...)

  • core.Permissions ->

Requesting the Permission Controller - {Files,Users,Themes}.permissions

This will see if the requested permission controller exist (e.g.: Files, Users, Themes, ..., ...)

  - DataBase

The EuroCMS Search Engine

The EuroCMS Core Search Core Component.

handlers

The supported handlers for now are:

  • Database

This will query the database for published content in the content database table.

  • Solr

code

There is no live code. But, here is the Abstract search code containing the following:

The "Search" class needs to have the folling functions:

Function

  • String("string") Push this to the Search Engine

  • Sanitize("$sanitize") Sanitize this string

  • Type("$Type) Search a specific type of the content: pages,files:pdf,images,binaries,etc...

  • domains("$domain")

Content code:

$QUERY = "SELECT * FROM content WHERE domain_id = '1' AND user_id = '1' AND group ='1' WHERE status = 'enabled";

$QUERY = "SELECT * FROM pages WHERE user_id = '1' AND group = '1' WHERE content like = '%$string%'";

Features:

  • all searches will be sanitized by default.

  • If you are allowed, search in domains

  • Search the type of content

Reference

The EuroCMS Session Core

A session is a way to store information (in variables) to be used across multiple pages.

Unlike a cookie, the information is not stored on the users computer.

Within PHP you can set your own session handler. Our ECMS session handler will secure and encrypt everything before saving it into it. Each component has a personal encryption tool that only the component can use, so encrypting data in $_SESSION, would be done by the component's encryption key.

# If the component type themes and the component name Skeleton saves data in the session array, like so:
$_SESSION["API_KEY"] = "1234567890";

# And access the its data:
echo $_SESSION["API_KEY"];

# Under water, the sessions are saved in $_SESSION["themes"]["Skeleton"]["API_KEY"].
# If the component type modules and the component name users, it would only access
$_SESSION["API_KEY"] = "ABCDEFGHIJKL";
echo $_SESSION["API_KEY"];
# It would output "ABCDEFGHIJKL", because it would only be saved in it's only environment.

# If, by some miracle, a hacker manages to get into a ECMS system, and wants to access the `$_SESSION`, and also manages to do so,
# And var_dump everything saved in `$_SESSION`, it would only see the encrypted version of the data.
# The hacker would need to have the enryption keys to decrypt the text. ECMS has many ways to manage encryption keys, File/MariaDB/SQLite, make sure to choose the options that's best secured for your environment.

# Secured component data
array(2) {
  ["API_KEY"]=>
  string(8) "{ENCRYPTED STRING}"
  ["USER_INFO"]=>
  int({ENCRYPTED STRING})
}

code

The code is hosted at: https://git.eurobytes.eu/imri/EuroCMS/src/branch/main/engine/core/core.Sessions.php

Reference

The EuroCMS Updates

This allows to manage and display updates for every ECMS component.

db structure

update_iddomain_iduser_idgroup_idcomponentnameupdatesseverityfuture_install_dateinstall_dateuser_lockstatus
1111modulesFiles1security20-05-2022 00:00:0020-05-2022 00:00:001Installed
2111modulesUsers1criticalnullnullnullskipped
3111coreUploads1criticalnullnullnullIgnored
4111themesSkeleton1criticalnullnullnulldelayed
5111widgetsNAVmenu1bugnull20-05-2022 00:00:00nullInstalled

The EuroCMS Core Uploads

What this core does:

Security Checks

When uploading a file this code checks the file:

  • if it already exists on the server

  • Size

If it does not exceed the allowed file size.

  • Mime type

If the mime type is allowed to be uploaded here

Reference

The EuroCMS VirusTotal

Find out where to put this example code?? Is this a library? A Core, Module, widget? Or all of them in one??

<?php

/**
*  Analyze suspicious files, domains, IPs and URLs to detect malware and other breaches, automatically share them with the security community.
*
* @param $id string SHA-256, SHA-1 or MD5 identifying the file
*
*/

// https://developers.virustotal.com/reference/file-info

class Virustotal {

	private $api_key = 'your api key';

	public $http_scheme = 'https';
	public $http_domain = 'www.virustotal.com';
	public $http_path = '/api';
	public $http_api_v = 'v3';

	public $http_api_header = 'x-apikey';

	public function GetaFileReport($id){
		// Retrieve information about a file
		// endpoint https://www.virustotal.com/api/v3/files/{id}

		$http_scheme = $this->http_scheme;

		$http_domain = $this->http_domain;

		$http_path = $this->http_path;

		$http_api_v = $this->http_api_v;

		$api_key = $this->api_key;

		$end_point = 'files';

		$url = "$http_scheme://$http_domain/$http_path/$http_api_v/$end_point/$id";

		return http::GET("$url", $header="http_api_header: $api_key");
		# json output

		// Responses: 200, 400

	}
}

The EuroCMS CLI Component

Authorversion
Imri Palojadraft

Make this a standalone cli?? Contemplate on things.

EuroCMS has a cli in the works. To manage your EuroCMS instance via Linux CLI.

ecli is mainly designed for maintenance purposes. For security reasons it cannot be executed out of the box. You need to create a user in ECMS, and that users needs cli permissions.

After that you can perform administrative tasks via cli.

Parameters

ecli has a list of main parameters, and sub parameters.

The options, arguments, parameters can be extended by installing modules.

If you Install the "Users" module, you get another argument, and options for the help,info,etc,, argument

list

The list option provides listing capabilities.

Options

  • --modules     - List all modules

  • --libraries      - List all libraries

  • --themes      - List all themes

  • --widgets     - List all widgets

  • --planner     - List all widgets

  • ...

info

Provides information regarding different components of ECMS

  • --modules {name} | {name1,name2,name3}

  • --libraries {name} | {name1,name2,name3}

  • --themes {name} | {name1,name2,name3}

  • --widgets {name} | {name1,name2,name3}

  • --planner {name} | {name1,name2,name3}

  • ...

remove

Remove different items in ECMS:

  • --modules {name} | {name1,name2,name3}

  • --libraries {name} | {name1,name2,name3}

  • --themes {name} | {name1,name2,name3}

  • --widgets {name} | {name1,name2,name3}

  • --planner {name} | {name1,name2,name3}

  • ...

help

Display help information regarding ecli, and or components

  • display ecli help

  • --users

  • --modules

  • --libraries

  • --themes

  • --widgets

  • --planner

  • ...

Modules

Module specific arguments. When a module is installed, every permission is also made available via cli.

users

example: ecli users(module name) add_users(permission name)

add_users | csv user info

cliargumentpermission namecsv(uname,fname,lname,pword,email,profile_pic,role,login_token,auth_methods,timezone,coc)
ecliusersadd_usersjd,John,Doe,PWORD,john@doe.nl,file_id,cli,null,creds,Europe/Amstedam,5

users_delete | csv of user_id

cliargumentparameter(permission name)csv of user_id
ecliusersadd_delete1

...

...

The EuroCMS Libraries

core.libraries.php can use the composer.phar software, to manage composer packages with.

We might be able to use the packa

Composer

Composer is a PHP package manager. https://getcomposer.org/

There is a composer.phar, that we can use with shell_exec to manage these PHP packages.

Or use the packagist API: https://packagist.org/ - this so that we can query with API pure.

Main characteristic

  • Installable

  • Deletable

  • Need permission to use them

backlog

A listing of libs that might improve EuroCMS somehow:

The EuroCMS commonMark library

Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)

Link

exiftool: read and write meta information in multimedia files

ExifTool is a platform-independent Perl library plus a command-line application for reading, writing and editing meta information in a wide variety of files. ExifTool supports many different metadata formats including EXIF, GPS, IPTC, XMP, JFIF, GeoTIFF, ICC Profile, Photoshop IRB, FlashPix, AFCP and ID3, Lyrics3, as well as the maker notes of many digital cameras by Canon, Casio, DJI, FLIR, FujiFilm, GE, GoPro, HP, JVC/Victor, Kodak, Leaf, Minolta/Konica-Minolta, Motorola, Nikon, Nintendo, Olympus/Epson, Panasonic/Leica, Pentax/Asahi, Phase One, Reconyx, Ricoh, Samsung, Sanyo, Sigma/Foveon and Sony.

Examples

exiftool::get('engine/Files/Uploads/image/jpeg/image-asset.jpeg');

Features

Reference

TrID - File Identifier

TrID is an utility designed to identify file types from their binary signatures. While there are similar utilities with hard coded logic, TrID has no fixed rules. Instead, it's extensible and can be trained to recognize new formats in a fast and automatic way.

example code

$trid = new trid();
echo $trid->analyze('/path/to/jpeg/file.jpg');

output

[
  [
    "75.0%",
    ".JPG/JPEG",
    "JPEG bitmap",
    "3000/1"
  ],
  [
    "25.0%",
    ".MP3",
    "MP3 audio",
    "1000/1"
  ]
]

Reference

The EuroCMS Modules

Modules are things that extend the functionality of the admin panel.

Main characteristic of Modules

  • Only interactable via the admin panel.

  • It and its feature can be protected with Access Control.

  • You can install and uninstall them

Most modules can have permissions that they can register. Those permission can be added to specific Roles by the admin.

Example permissions:

namedescriptionCoC?
{ModuleName}_addThe ability to add things1
{ModuleName}_removeThe ability to remove things
{ModuleName}_modifyThe ability to modify things

Register the permission to a specific hierarchy? System Roles??

There is a users_history permission, where you can view, the history of the user.

If an Editor role user, has this permission, that user can view the history of the Admin or owner user. So, you are viewing the history of someone higher in rank.

If you have a CoC(Chain of Command or hierarchical command), you can only view the history of a user that is lower in the hierarchical command. The Owner user can view everything below him, but no one can view anything beneath him.

List Of Modules

The EuroCMS About Module

This is the EuroCMS about page, this display everything about EuroCMS.

The below content is inspired from the builtin Roundcube about page from the version.

EuroCMS 1.0.0

Copyright © 2022, The EuroCMS Team

EuroCMS is modular, in that it is divided in several different type of components. These components can be distinctly managed.

namecomponentauthorversionlicensehomepageSize
FilesmoduleImri Paloja1.0.0EuroCMS - Modules - Files500KB
SkeletonThemesImri Paloja1.0.0EuroCMS - Themes - Skeleton250KB
NewUbuntuReleaseWidgetsImri Paloja1.0.0EuroCMS - Widget - NewUbuntuRelease20KB
UploadscoreImri Paloja1.0.0EuroCMS - Core - Uploads5KB
exiftoollibrariesImri Paloja1.0.1EuroCMS - Libraries - exiftool25KB

Reference

The EuroCMS Analytics module

View analytics data

db structure

SESSIDdomain_iduser_idgroup_id...USER_AGENT............

TODO:

  • Rename PHPSESSID to SESSID in code, per the OWASP recommendations.

  • Incorporate proper graphs:

https://www.chartjs.org/ ? example available here: https://jsfiddle.net/blade1989/4urxwnj1/6/

Reference

The EuroCMS Backup module

Choose what you want exported, then get a zip,tar.gz or tar.xz as export file.

This file can also be restored.

The importing and exporting, is very simple. Choose what you want to import, choose what you want to export.

Or just choose everything.

NOTE: Make sure the backup is handled server side! That is *the* most complete and save way of backing up.

The EuroCMS Cache Module

AuthorVersion
Imri Paloja1

This is a local cached example

The generated content of ECMS Themes, templates and Widgets can be cached, you can also delete those cached files, and regenerate them if needed.

Settings

  • Changed cached time.

  • Minify: CSS, JS, HTML, XML, JSON, ..., ...

  • Compress and resize images

  • View cached Sizes: per domain, theme, widget, file

  • Delete cached files for specific components: core, module, widgets

  • View cached sized per domain, and or components.

  • Disable caching per domain. This is useful when a domain is just a redirect to the main domain.

  • Disable caching per component

Folder structure

/engine/cache

  • example.nl/
    • themes/
      • Skeleton/ (theme name)
        • Skeleton/ (template name)
          • tutorials/
            • how-to-do-a-thing
            • how-to-do-a-thing-banner.png
            • portable-document-file.pdf
            • Skeleton.css.Skeleton.css (will be loaded inline)
    • W3schools/ (theme name)
      • band_page/ (template name) (template name)
        • tours/
          • Europe/
            • Amsterdam
              • Amsterdam-tour-2009.png
              • Registration.pdf
              • W3schools.css.band_page.css (will be loaded inline)
              • W3schools.js.band_page.js (will be loaded inline)

cache db structure

cache_iddomain_iduser_idgroup_idcomponent_typecomponent_namenameuser_lockstatus
1111themesskeletonSkeletoncached
1211corecontent/tutorials/how-to-do-a-thingoutdated
  • cached: This is already cached

  • outdated: The database contains newer information.


Reference

  1. https://cloudinary.com/blog/image_optimization_in_php

  2. https://www.google.com/search?q=PHP+compress+images

  3. https://www.w3schools.com/tags/tag_picture.asp


The EuroCMS Configure Module

This module allows you to manage settings per domain.

DB structure

configure_iddomain_iduser_idgroup_idhttps_redirectkeywordsauthortitlethemetemplateip_denyip_allow......user_lockstatus
1111truetutorials,editoralsauthorEuroBytes - free tutorialsSkeletonSkeleton127.0.0.1127.0.0.11enable

Permissions

namedescriptionCoC
configure_modifyModify configure settings

The EuroCMS Cookie Module

Our Analytics module, is a server side tracking one. It does not track you beyond the EuroCMS installation. Your user agent, and IP address information is stored. Your IP is encrypted before being saved in the DB.

Next to that, by default EuroCMS does not have third party tracking cookies. But, when installed, you can add and modify things to add Google Analytics and such. These *can* introduce to a EuroCMS installation.

By default, EuroCMS tries to detect which installation are adding Third Party Tracking cookies, and add that to the cookie box.

Also make core.cookies.php ?

db  structure

If a cookie is being detected, the message will be displayed, and you can choose it to add in the cookie box.

cookie_iddomain_iduser_idgroup_idcookie_namecookie_descriptioncategorycookie_idcookie_domaincookie_expireshttpOnlypathsamesitesecurevalue
1111EuroBytesDeze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring.Functioneel en analytischebs-id.eurobytes.eu2023-05-31T12:36:08.000Ztrue/Laxtrue686bf5f0-e6be-4e6c-98b7-9bd2e2747850

Reference

The EuroCMS Customers Module

AuthorversiondateStatus
Imri Palojadraft22-03-2023Contemplating

This module will be used to manager customers for eurobytes.eu. For now. Later on we might add this module as a group for the EuroCMS Webshop plugin.

db structure

The customers db table

customer_iddomain_iduser_idgroup_idcompany_nameunameemailfnamelnamepwordorderuser_lockstatus
1[0-9][0-9][0-9]Example Incjdjohn@doe.euJohnDoe${PWORD}{JSON}1enabled
2[0-9][0-9][0-9]Jane Doe Photographyjdpjane@doe.euJaneDoe${PWORD}{JSON}1enabled

Permissions

The modules builtin permission list

namedescriptioncoc?
customer_addThe ability to add content
customer_removeThe ability to remove content
customer_modifyThe ability to modify content
customer_restoreThe ability to restore content

Order json example

{
   "server": {
      "location": "random",
      "image": "EBS-CX11-Ubuntu-2204-amd64",
      "type": "CX11",
      "networking": {
         "PUBLIC_IPV4": true,
         "PUBLIC_IPV6": true,
         "SSH_KEYS": ""
      },
      "volumes": {
         "name": "volume-1-data",
         "file_system": "ext4"
         "size": "10G"
      },
      "firewalls": [
         "webs"
      ],
      "backups": {
         "enabled": true,
         "type": "incremental",
         "intervals": 24
      }
   },
   "IP": "127.0.0.1",
   "app": "WordPress"
}

The EuroCMS dashboard

If components like core, modules, widgets and or themes have dashboard files, they will be listed in the dashboard view.

With the "+" button able to add other dashboard files.

Examples

Analytics dashboard

  • Total visitors

  • Most viewed pages

  • Top visitors (by country)

Files dashboard

  • Recent added files

  • Top files sorted by file type

  • Most viewed files

User dashboard

  • Recent Users

  • Users with most articles

  • Users with most viewed content

Content dashboard

  • Recently posted content

Comments dashboard

Disqus or homemade comment box.

  • Recently posted comments

  • Most liked comments

  • most downvoted comment

  • Most upvoted comment

Permissions

namedescriptioncoc?
dashboard_addThe ability to add dashboards
dashboard_deleteThe ability to delete dashboards
dashboard_modifyThe ability to modify dashboards

The EuroCMS Domains Module

EuroCMS, out-of-the-box, comes with multi domain support.

This will allow you to add different domain names, to EuroCMS.

The types of domain it can be are:

  • website: When people visit this website, the'll see the standard theme.

  • redirect: When people visit this website, they'll be redirected to whatever it was redirect to.

e.g: visiting example.com redirects to example.eu.

  • Module: If people visit this website, they'll get a specified module.

For instance, you can add website, named admin.example.eu, and load the admin module, so that you'll always get admin panel.

The module can add support for this, such as the api module. You can add a website named api.example.eu, when visiting you'll get a json output of the features that public domain is allowed to view.

  • Alias:

Every settings is loaded exactly as the main domain. Including themes, users, groups, etc...

db structure

domain_iduser_idgroup_idnametypeuser_lockstatus
115eurobytes.nlwebsite12,45enabled
214eurobytes.netredirectenabled
313api.eurobytes.nlmoduleenabled
412eurobytes.comaliasenabled

Permissions

namedescriptioncoc?
domains_addThe ability to add domains
domains_deleteThe ability to delete domains
domains_modifyThe ability to modify domains

The EuroCMS Error Module

EuroCMS uses a custom error handler, which saves the error in the DB. Which this Module, you can view and delete the error module.

db structure

error_iddomain_iduser_idgroup_iderror_dateerr_numbererr_stringerr_fileerr_linemessageuser_lock
11111

The EuroCMS Error Pages

You can modify error pages from EuroCMS.

db structure

error_pages_iddomain_iduser_idgroup_idhttp_statusnametitlekeywordsthemetemplateuser_lockstatus
111null404Not foundThe page could not be found404,not,foundenabled
211null500Internal server errorThere was an internal server error500,internal,server,errorenabled
311null401ForbiddenYou do not have the needed rights to see this.400,internal,server,error1,2enabled

By default the domain theme and template are used. But, if you require a separate theme and template to be loaded for a specific error page, you can also do that.

Permissions

namedescriptioncoc?
error_pages_addThe ability to add error pages
error_pages_deleteThe ability to delete error pages
error_pages_modifyThe ability to modify error pages
error_pages_themeThe ability to modify the theme and templates for the error page

Reference

The EuroCMS EuroEditor

This allows you to edit and modify content on the page.

Need to request permissions from the content table to view and edit the content.

The content table needs to have an edit button, that'll push to the EuroEditor. The rights and permission for this needs to be enabled.

Check out: https://github.com/mdn/browser-compat-data

Document.execCommand is deprecated. Writing JS code that'll do what execCommand can do out of the box, takes time.

Alternative is to use markdown, and convert it to readable code? Live convert?

<?php

$count = '0'; $content = '<p>Test</p> <p>Kaas</p>';

$max_number = substr_count($content, '<p>');

echo "$content\n";

echo "$max_number\n";

echo str_replace('<p>','<p id="1">',$content);

Contemplate

  • Cross module rights permissions?

EuroEditor Group/Users? Add any module into this group that want permissions?

Or requests permission directly. Make it a per permission based things???

Permissions

namedescription
euroeditor_addThe ability to add content into the content db table.
euroeditor_deleteThe ability to delete content from the content db table.
euroeditor_modifyThe ability to modify existing content in the content db table.
euroeditor_varsThe ability to create and modify variables and using them in different pages.
euroeditor_ipThe ability to IP protect a content in the content db table.
euroeditor_ajaxThe ability to add AJAX content into the content db table.
euroeditor_objectThe ability to add auto generated files from variables(robots.txt/sitemap.xml/contribute.json), into the content db table.

euroeditor_vars

Click the vars button, a popup window will appear, where you can manage vars

namevalueDelete
latest_lts_version22.04X
latest_lts_nameJammy JellyfishX
......X

Screenshot

EuroEditor Screenshot

EuroEditor

Custom HTML Elements

To generate unique content on the front end, we will register a new HTML tag.

First, we need to register the new html elements via JS code, like so:

/*
	When the browser is done, loading, get the ecms tags
*/
class ECMSElement extends HTMLElement {
    connectedCallback() {
/*         this.innerHTML = `<h1>Hello World...</h1>`;
        this.style.color = "red"; */
    }
}

customElements.define('ecms-content', ECMSElement);

// https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
window.onload = function GetData() {
	const ecms = document.querySelectorAll('ecms-content');

	for (i = 0; i < ecms.length; i++) {
		console.log(ecms[i].dataset);
		alert(ecms[i].dataset);
	}
}
// Concept code. Later on, the ecms tag will be replaced with the requested content code.
// https://jsfiddle.net/blade1989/s81mr4gj/

HTML code

<!-- One generic EuroCMS tag? -->
<ecms-content data-file='007'></ecms-content>
<ecms-content data-toc></ecms-content>
<ecms-content data-form='789'></ecms-content>

<!-- Or per type of content?? -->

<!-- Files -->
<ecms-file data-fid='001'></ecms-file>

<!-- Table Of Content -->
<ecms-toc title="Table Of Content" data-collapse='true'></ecms-toc>

<!-- Forms?? This would work wonders for forms -->
<ecms-form title="Contact Form" data-form='789'></ecms-form>

Output

<h1 style="color: red;">Hello World...</h1>

<!-- ecms files -->

<a href="/files/image/png/file.png" title="file.png">
	<img src="/files/Thumbnail/png/w160-file.png" alt="file.png">
</a>


<!--

Things to remember

 - Lazy loading?
 - viewport loading at onload?

-->

HTML Global Attributes

The global attributes are attributes that can be used with all HTML elements.

AttributeDescription
accesskeySpecifies a shortcut key to activate/focus an element
classSpecifies one or more classnames for an element (refers to a class in a style sheet)
contenteditableSpecifies whether the content of an element is editable or not
data-*Used to store custom data private to the page or application
dirSpecifies the text direction for the content in an element
draggableSpecifies whether an element is draggable or not
hiddenSpecifies that an element is not yet, or is no longer, relevant
idSpecifies a unique id for an element
langSpecifies the language of the element's content
spellcheckSpecifies whether the element is to have its spelling and grammar checked or not
styleSpecifies an inline CSS style for an element
tabindexSpecifies the tabbing order of an element
titleSpecifies extra information about an element
translateSpecifies whether the content of an element should be translated or not

Markdown editor

dependencie: https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js

showdown.js:

// Simple
var converter = new showdown.Converter(),
    text      = '# hello, markdown!',
    html      = converter.makeHtml(text);

// -
// complex
var converter = new showdown.Converter(),
    MarkDownContent = document.getElementById("markdow").innerText;
    HTMLContent		= document.getElementById("html").innerHTML;

    ConvertedToMarkDown = converter.makeMarkdown(HTMLContent);
    ConvertedToHTML		= converter.makeHtml(MarkDownContent);

alert(ConvertedToHTML);

Reference

The EuroCMS Files Module

A File manager module for EuroCMS.

  • Read the metadata of 200+- supported file types(exiftool)

  • Edit images(not yet implemented)

  • On upload, if possible, the metadata of every file stripped.

Contemplate

  • File Names

The file names are uploaded to a dir: Files/image/png/file.png. If a file of the same name is uploaded, it will overwrite the other one.

Rename the file from file.png to {hash}.png? or just {hash}?

  • default group?

Create some groups during install? Themes group? Like themes?

Every component can have their own group and upload files/images in the group, so that the rest can't see them and also won't clutter their view with ALL of the files?

Yes. excellent idea!

Storage handlers

The aim for now is to add Local and WebDAV support for uploading files.

  • Local

  • WebDAV

In the future, I'll look into making more Storage Handlers.

Or let the community decide which one they want to build.

Ajax upload steps to check the files uploaded

  • Check the file type('\.[a-zA-Z]*$')

  • Start validation method depending on the file extension.

  • If validation failed, reply with the reason of failure

  • If succeed, the png file is actually a PNG file.

  • See if the mime type is allowed to be uploaded

  • ...

  • Check the file size

  • Upload the file.

  • ...

Security

Execute permissions

When uploading a file with special rights and or permission, make sure they are not implemented on the server. Set the rights to 600! or 000?

Viruses

You don't want users to upload Viruses to your ECMS. That's why I am thinking to implement VirusTotal and or other services.

What it will do, when uploading the file, a hash of the file will be generated, and that hash will be sent to VirusTotal and or others, via API. And if VirusTotal says it is a virus, the file will not be uploaded.

And there will be a notification sent to the domain administrator.

If the file is not known to viruses, and or the file is clean, it will be allowed to upload to ECMS.

Permissions

The list of available permissions this installs.

namedescription.........
files_addThe ability to upload files
files_deleteThe ability to delete files
files_modifyThe ability to modify files
files_metadataThe ability to read metadata from files
files_usageThe ability to view where the file is used.
Check if the role is of a higher role? Can a regular users with the users_history, permission view the history of the Owner/admin user?

Structure

Just a snippet of the rows it supports.

file_iddomain_iduser_idgroup_idpathnamegrouptitledescriptionlocal_pathupload_datetypemimetypemetadatahashthumbnailuser_lockstatus
111null/image/png/file.pngfile.pngPNGsFileThe file.png/engine/Files/Uploads/image/png/file.png{date}pngimage/png{exiftool json output}{md5 hash}/engine/Files/thumbnails/image/160-File.pngnullenabled
111null/image/jpg/file.jpgfile.jpgJPGsJFILEThe JFILE/engine/Files/Uploads/image/jpg/file.jpg{date}jpgimage/jpg{exiftool json output}{md5 hash}/engine/Files/thumbnails/jpeg/160-File.jpgnullenabled
111null/image/jpg/file.pdffile.pdfPDFspdfThe pdf/engine/Files/Uploads/application/pdf/file.pdf{date}pdfapplication/pdf{exiftool json output}{md5 hash}/engine/Files/thumbnails/pdf/160-pdf.jpgnullenabled
111null/image/jpg/file.jpgfile.jpgJPGsJFILEThe JFILE/engine/Files/Uploads/image/jpg/file.jpg{date}jpgimage/jpg{exiftool json output}{md5 hash}/engine/Files/thumbnails/jpeg/160-File.jpgnullenabled

The EuroCMS Forms Module

AuthorRevisiondate
Imri Palojadesign20-05-2022

The HTML form is generated using custom html tags. This is to trick the casual bots that are programmed to search and abuse any forms they find online.

For the 'hacker' that goes the extra mile, so actually sit in front of the website, and manually try to hack it, the following precautions have been implemented:

The ECMS Form structure uses Ajax to process the form data. The Ajax Form POST link, is auto generated, it is saved server side as a variable, and used later on, to let the Ajax controller know, where to POST the data.

A UID is generated every time a form is loaded. That UID is checked every time the user submits a form. If they don't match, or is none existing, the form will not be processed.

So, lets say the hacker has the UID, and the unique path of the Ajax request, all the form data are validated, sanitized, and the HTML entities are escaped.

https://austingil.com/how-to-build-html-forms-right-security/

https://developer.mozilla.org/en-US/docs/Learn/Forms/Advanced_form_styling

https://developer.mozilla.org/en-US/docs/Learn/Forms/Sending_and_retrieving_form_data

https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation

# Steps,

1. Type in form name: 2. Select form element(input,textarea)  A. `input` selected  B. Select type of input(text, url,email)  C. input type text selected  D. Select attributes: Attributes     # Add new form

## Blank window appears with "select form elemts" text.

Popup drop down appears with the following:

- <input> - <textarea> - <button> - <select> - <option> - <optgroup> - <fieldset> - <label> - <output>

## input select Input tag is inserted in the blank window. Click the gear icon, and add input type attributes

DB structure

form_iddomain_iduser_idgroup_idform_nameformuser_lockstatus
1111contact{JsonBlob}1enabled

The HTML <form> Elements

The HTML <form> element can contain one or more of the following form elements:

  • <input>

  • <label>

  • <select>

  • <textarea>

  • <button>

  • <fieldset>

  • <legend>

  • <datalist>

  • <output>

  • <option>

  • <optgroup>

HTML Input Types

Here are the different input types you can use in HTML:

  • <input type="button">

  • <input type="checkbox">

  • <input type="color">

  • <input type="date">

  • <input type="datetime-local">

  • <input type="email">

  • <input type="file">

  • <input type="hidden">

  • <input type="image">

  • <input type="month">

  • <input type="number">

  • <input type="password">

  • <input type="radio">

  • <input type="range">

  • <input type="reset">

  • <input type="search">

  • <input type="submit">

  • <input type="tel">

  • <input type="text">

  • <input type="time">

  • <input type="url">

  • <input type="week">

HTML Input Attributes

Here are the different input Attributes you can use in HTML:

  • value

  • readonly

  • disabled

  • size

  • maxlength

  • min|max

  • multiple

  • pattern

  • placeholder

  • required

  • step

  • autofocus

  • height:width

  • datalist

  • autocomplete


Type;name;attributes:value

# Examples of input_fields


Type;name;attribute:value:attribute:value


text;fname;John;disabled,text;lname;John;readonly,
text;number;John;size:20,text;year;John;maxlength:20:size:20,
number;number;John;min:18:max:80,file;Files:multiple,
text;country_code;pattern:[A-Za-z]{3}:title:Herro&nbsp;?

Reference

The EuroCMS Help module

This will display every help page that is registered in ECMS.

output structure:

EuroCMS

This will display all the documentation on ECMS for the user.

Modules

This will display all of the registered help pages by the modules.

Files

  • Uploads

  • Storage Handlers

  • ...

Widgets

Themes

Translation: https://www.transifex.com/open-source/

The EuroCMS Ini Module

This will allow to modify Core PHP Settings!

via the PHP set function

Reference

The EuroCMS Installer Module

AuthorVersion
Imri Paloja1

This is the Installer module. You only can view this during first install.

In steps what the installer does.

Features

  • INSTALLER_MODULES_INSTALL

This will display all the available modules to install via the installer.

Step 1: ips.txt

Check if the /ips.txt file exists. This file needs to exist in the root directory of the project folder, next to the index.php file.

With the ips.txt file you can IP protect the Installer. This is so that no one else in the world can access your installer.

The text file supports one IP per new line in the ips.txt file.

Example:

127.0.0.1
127.0.0.2

Then, save your ips.txt file, again, next to EuroCMS index.php file.

At first install, your /ips.txt, will be read, and if the IP address of the visitor does not match the IP in the ips.txt file, the script will not continue with the installation.

Step 2: Dependencies

Dependencies will be checked for every ECMS component:

  • core

  • libraries

  • modules

  • widgets

The type of dependencies can be PHP modules, or other Linux binary files like exiftool.

EuroCMS needs certain php modules installed. It will check if those are installed. If they are not, it will not continue, with the installation, until the dependencies are installed.

EuroCMS will display the modules needed, and if the information is available for your Linux distro, also display installation steps for the missing dependencies.

Step 3: Installation form

After the /ips.txt and dependencies check has passed, you get the installation form, where you can fill in your:

User credentials

  • user name

  • first name

  • email

  • password

Fill in your database credentials:

For now, the only supported DB is MariaDB.

  • hostname

  • password

  • username

  • port

Step 4: Installing

If the INSTALLER_MODULES_INSTALL installer options is set to true, the modules tab with all the available modules to install, are shown.

The modules that were selected will be installed, this is done in the following ways:

This examples uses the Files modules

  • Check module requirements()

The Files/requirements.json file of every selected modules will be read and it's settings will be applied. Such as, but not limited to: sql databases, feature permissions, Dashboards, Planner items, ajax url, license acceptance.

  • Set in the modules database table, the activated modules.

Finished installation

After the installation has finished, you will de redirected to the website, and from /admin you can login with your user credentials.

And from their on, you can manage your EuroCMS website.

Browse the EuroCMS modules, to view what you can do with EuroCMS.

Contemplate

These are idea to think about for future versions.

Read Only Files?

For a module developer, make available a READ_ONLY option, with the following available options:

  1. ALL - where every file, during module installation is made read only, via file system, using chattr.

  2. file.json, file.php: a comma seperated list of files that need to be read only.

  3. dynamic: comma separated list of files to make read only, that will exist in the future.

Benefits

  • Security

The files can never be modified, by malicious code, should there ever be such a thing.

  • Trust

Features like these build trust within the user base and community, that EuroCMS has all possible security options readily available for whatever environments that it maybe installed on.

Drawbacks

  • Does complicate the overall ECMS project?

Dependencies

  • Chattr?

chattr is a Linux CLI, that allows you to "change file attributes on a Linux file system". Meaning you can make specific files, non editable.

Not by default supported in PHP. So, the best we can do is a ~~shell_exec("chattr +i \"$file\"");~~.

Apparently it is supported: https://www.php.net/manual/en/ref.xattr.php

Per step installation?

Fill in user credentials, AJAX to validation.php,  get sent validation e-mail, get return token input field, paste token, token passed, Ajax return database credentials input fields, check if they are correct, installation passed. redirect to /.

Automatic installation

via curl, and some custom headers, authentication, you can install everything you need automatically.

The EuroCMS Libraries Module

This is the managing module for the EuroCMS libraries component.

What are libraries? Use composer packages? Query the https://packagist.org/ packages? Build a Libraries module that uses the packagist API to query for packages?

db structure

library_iddomain_iduser_idgroup_idnameversionchannelauthordescriptionlicenseaccept_licenseuser_lockstatus
111trid1.0.1stableMarco Pontellotrid - file analyzerGPL2trueenabled
211exiftoolPhil Harveyexiftool - metadata reader/writerGPL2trueenabled
  • exiftool: you can use the system installed version, or download and install the exiftool version yourself.

This is just in case hosting providers don't want to install extra packages in your system.

Nonetheless, one could write an update script, to update packages from the main trid website. Or, use the repo module, and have the repo module scrap the changelog version, gpg and etc...

TODO

Write a proper manager of libraries controller:

  • Update

  • Delete

  • Modify

The EuroCMS Login module

Future auth methods:

All of these can be enabled. Or one of these can be enabled separately?

  • Credentials (functional)
  • E-mail (not yet implemented)
  • Telegram?

MFA methods:

Multi-factor authentication methods

  • SMS Token Authentication. ...
  • Email Token Authentication. ...
  • Hardware Token Authentication. ...
  • Software Token Authentication. ...
  • Phone Authentication. ...
  • Biometric verification. ...
  • Social Login. ...
  • Security Questions.

Top 10 Multi-Factor Authentication (MFA) Software

  • Duo Security.
  • Google Authenticator.
  • Microsoft Authenticator.
  • Authy.
  • LastPass.
  • RSA SecurID® Access.
  • OneLogin.
  • Ping Identity.

Screenshot

The EuroCMS Login Panel

Reference

The EuroCMS Logout module

If you access the /admin/logout link, you will be automatically logged out and the predefined data will be cleared.

logout_iddomain_iduser_idgroup_idnameshort_descriptionredirectcontentclearuser_lockstatus
111Sessiondefaults, clears the entire session data/loginsession1enabled
221allClear all data associated with the Logged in user.Your data has been destroyed.Session, Cookies, Storage, Cache
  • redirect (optional)

Redirect the users when the /logout link has been accessed. /login or / the homepage.

The redirect is set via a header, so before the content has been even loaded, the browser has been told to visit a different page.

  • content

If the redirect is not used, what you want to be displayed on the logout page?

Your session data on this websites will be cleared?

The content can be written with EuroEditor. You can add a redirect page that'll redirect the user 10 seconds after visiting the logout link.

clear options:

  • cookies

  • session

  • storage

  • cache

The Clear Site Data header can already do this, but as of yet, not all browsers support this.

The EuroCMS Notifications module

This will display every notification you have accesss to, it will allow you to delete and read in full the messages.

But, also, apply rules, for which type of notificaion deserve an E-mail/Telegram and such.

Also actions? Like delete tmp/ contents, if the size of tmp has passed a certain size?

Notification channels

The default notification channels:

  • Local(MariaDB/PostgreSQL)

  • E-Mail

Future notification channels

  • Telegram

  • Webhook

  • Mattermost Message in a channel

  • OpenProject Creates tasks

Permissions

A list of builtin permissions by the notifications

namedescriptioncoc?
notifications_addThe ability to add notifications
notifications_removeThe ability to remove notifications
notifications_modifyThe ability to modify notifications

The EuroCMS Pages

This holds the Content, pages, posts, articles you create. For example your  /contact, /about and also your /tutorial/how-to-install-EuroCMS.

Type of Pages:

  • tutorial

  • editorial

  • article

  • blogpost

https://english.stackexchange.com/questions/167241/difference-between-article-tutorial-how-to-course-track

Difference between Article and Blog

"The most noticeable difference between a blog and an article is the difference in writing style and the length of the piece. Blogs can range anywhere from 300 to 1000 words, but articles are often much lengthier. Depending on the publication, the standard length of an article can vary from 1500 to 5000 words." - https://yourstory.com/2017/02/difference-between-blog-article/amp

More detailed: https://www.geeksforgeeks.org/difference-between-article-and-blog/:

S.No.ARTICLEBLOG
01.Articles are more than 300 words and sometimes more than 1000 words.Blogs are less than 300 words and sometimes less than 1000 words.
02.It is written in second or third person.It is usually written in first person.
03.Articles should be lengthy and detailed.Blogs can be short or long it depends.
04.It does not include personal opinions.It includes personal opinion.
05.Reader has time to search and analyze and understand what the article is about.Reader is somewhat impatient and reads casually so contents should be quick to grasp.
06.It is based on sophisticated writing skill.It is based on casual writing skill.
07.Keywords are not important in articles.Focusing on keywords while writing blog.
08.Articles are based on interview, research, explanation, analysis or report and fact based.It is not based on interview or research. It contains tips, lessons, opinions and tools etc.
09.It is not SEO optimized.It is SEO optimized.
10.It includes lots of data, graphs, required images and statistics.It usually includes one or more images.
11.Editor and Reviewer teams need to verify before publishing.It is self publishing and does not require editor or reviewer verification.
12.It is not required to be frequently updated.It is required to be frequently updated.
13.It can share education information, state or facts.It can share opinions, encourages, and insights.
14.Articles are arranged by category.Blogs are arranged by chronologically.
15.For example writing any research article in IEEE.For example writing any blog in medium.

db structure

Database table name: Pages. In the future I might add auto generated table names for the database structure.

pages_iddomain_iduser_idgroup_idpageauthorpost_datenametitlelocal_pathlangtypecategoryintrocontent_imagecontentkeywordsWidgetshttp_methodscspcharsetuser_lockstatus
111/John{post_date}1enpageindexThis is our home page/favicon.pngNavMenuGETutf-8published
211/contactJaneenpagecontact/favicon.pngNavMenuGETutf-8draft
3115/tutorials/howto-install-EuroCMSenpageindex/favicon.pngNavMenuGETutf-8waiting_for_review
4113enpage/favicon.pngNavMenuGETutf-8denied
enpage/favicon.pngNavMenuGETutf-8

Permissions

The modules builtin permission list

namedescriptioncoc?
pages_addThe ability to add content
pages_removeThe ability to remove content
pages_modifyThe ability to modify content
pages_restoreThe ability to restore content
pages_user_lock

The EuroCMS Planner

authorversiondate
Imri Palojadraft24-07-2022

Here is where you setup which code is allowed to be executed at an interval.

db structure

plan_iddomain_iduser_idgroup_idcomponent_typecomponent_namenamedescriptiontaskstime_intervaluser_lock?status
1111coreupdatesUpdatesCheck for updatesUpdatesevery_minute1enabled
2111MaintenanceExecute various maintenance tasksDiskUsage,CleanTmpFiles,FilePermCheckevery_hour1enabled
3111ValidateEuroCMS File validation; make sure no one has modified our files.ECMSFValidation,every_day1enabled
4111modulesTrashTrash cleanupDelete 30+ days filesTrash deletionevery_day1enabled

Tasks

  • Updates

Check if ECMS has updates. And also check of update have been set to a future installation date.

  • DiskUsage

Check if the disk usage is passed a certain percentage.

  • CleanTmpFiles

Everything in the engine/tmp/ - will be removed after X amount of times...

  • FilePermCheck

Make sure that if you set a file to 600, and to the proper owner, that the Webserver (NGINX, Apache) user is allowed to access those files.

  • ECMSFValidation

Make sure that our files have not been modified.

Permissions

namedescriptioncoc_id?
planner_addThe ability to add planner items1
planner_removeThe ability to remove planner items
planner_modifyThe ability to modify existing planner items
planner_logsThe ability to view the planner logs
planner_

The EuroCMS Profile Module

The EuroCMS profile module allows you to change your user settings.

username and e-mail are not changeable.

Things you are able to change

  • Display name
  • First name
  • Last name
  • Profile picture
  • Time zone
  • password
  • theme
  • API keys(if you have API permissions)
  • authentication method(if not hard set by your admin)
  • theme

Here you can view the group(s) you are in, your Role, and the permissions you have.

basically everything from the users module, that you have the rights to.

DBs it can modify:

  • users (users own info)

The EuroCMS Repo module

Make this a monthly subscription option.

After purchase the HASH is generated using the uname,pword

Repo table structure

ecms_iddomain_iduser_idgroup_idfqdnsignaturevalidatedstatus_messageuser_lockstatus
111nulltest.nl{sha512}true1enabled
211nullexample.eu{sha512}falsePlease complete the validation steps.1disabled

ECMS Table structure

repo_iddomain_iduser_idgroup_idnamecomponentspwordsignaturehttpsHTTP_HOSTpathstatus
1111EuroCMSCore,Libraries,Modules,Themes{bcryptPassword}{sha512}truerepo.eurocms.eu/repo.jsonenabled
2111ThemesThemes{bcryptPassword}{sha512}truethemes.eurobytes.eu/repo.jsonenabled

The sha512 sum is generated depending on info depending during installation.

First 2 character of the string is the startup. After the 2 characters, there is a dash suffixed. After that, after every 6 characters there is a dash suffixed, For example:

85-0c28ec-681a90-f5c239-4680e7-bdcf9d-381523-f91876-1e7cef-e4e92b-5eb3fe-fd27df-7b6ea3-66d065-2993b8-679fd1-db9e50-1a2cac-4f3e2b-d48fe9-b3e375-511d89

The hash is generated using values of uname, fname, email input fields during installation...

Certificates

Protect the connection between the repo and the ECMS installation, using certificates.

https://www.php.net/manual/en/openssl.configuration.php

https://wpquark.com/kb/misc/server-management/fixing-curl-ssl-connection-issue-php-ini/

https://www.devdungeon.com/content/how-use-ssl-sockets-php

repo.json

{
  "EuroCMS":{
    "components":{
      "Core":"Core/Core.json",
      "Modules":"Modules/Modules.json",
      "Widgets":"Widgets/Widgets.json",
      "Themes":"Themes/Themes.json"
    }
  }
}

Example Modules.json :

{
  "Modules":{
    "Users":{
      "pretty_name":"The EuroCMS Users Module",
      "version":"0.0.1",
      "favicon":"",
      "thumbnail":"",
      "short_description":"Basically, in the `Users` section of this json, the contents of the metadata.json, permissions, and dependencies.json are displayed, with some added content needed for repos",
      "long_description":"html entities escaped content",
      "release_channel":"You can put here: concept,pre-alpha,alpha,beta,release-candidate,stable"
    }
  }
}

All in one example. If there are duizends or more, this might not be preferable.

{
  "EuroCMS":{
    "components":{
      "core":{

      },
      "Modules":{
        "Users":{
          "pretty_name":"The EuroCMS Users Module",
          "version":"0.0.1",
          "favicon":"",
          "thumbnail":"",
          "short_description":"Basically, in the `Users` section of this json, the contents of the metadata.json, permissions, and dependencies.json are displayed, with some added content needed for repos",
          "long_description":"html entities escaped content",
          "release_channel":"You can put here: concept,pre-alpha,alpha,beta,release-candidate,stable"
        }
      },
      "Widgets":{

      },
      "Themes":{

      }
    }
  }
}

Reference

The EuroCMS Routes Manager

authorversiondate
Imri Palojadraft06-09-2022

As of writing this still needs to be renamed to the Routes manager in the actual code.

Routes manager for EuroCMS.

With Routes Manager you can register a REQUEST_URI, IP protect the content, select which content to load from other objects in the current domain.

For example: files, modules, pages(articles,blogposts, etc...). You can register the /api url, and have the API module handle the requests of that URL, and also IP protect the URL.

You can also create routes, like robots.txt, humans.txt, sitemap.xml. These have a builtin generator.

You can make custom db queries for when someone accesses a specific url. For example, when someone accesses /modules, you can make it query the modules dir, and have it output it in a json format. Figure out how to code this.

DB table structure

route_iddomain_iduser_idgroup_idrequesttabletable_nametable_idip_denyip_allowpworduser_lockstatus
1111/tutorials/how-to-eurocmspagespage_id34nullnull{BCRYPT}1enabled
211/apimodulesmodule_id54all127.0.0.2null3,5enabled
311/file/file.pngfilesfile_id5nullnullnullnullenabled
411/robots.txtobjectobject_id50nullnullnullnullenabled
511/hackers.txtobjectobject_id52nullnullnullnullenabled
611/sitemap.xmlobjectobject_id55nullnullnullnullenabled
711/Files/FileUploadajaxajax_id2127.0.0.1127.0.0.2nullnullenabled
811/modules.jsonfilesfile_id100nullnullnullnulldisabled
9111/api/users ??? contemplate on the whole rowapiapi_id54all127.0.0.1,127.0.0.2{BCRYPT}nullenabled

Permissions

namedescription
route_addThe ability to add routes
route_deleteThe ability to delete routes
route_modifyThe ability to modify existing routes
route_ipThe ability to IP protect a routes
route_ajaxThe ability to add AJAX routes
route_objectThe ability to add auto generated files from variables(robots.txt/sitemap.xml/contribute.json)

Objects

You can add an object as a content. That is a special file, either hard pasted or auto generated from databases. Here are some examples:

robots.txt

https://developers.google.com/search/docs/advanced/crawling/overview-google-crawlers

https://developers.google.com/search/docs/advanced/crawling/verifying-googlebot

https://developers.google.com/search/apis/ipranges/googlebot.json

sitemap.xml

When you create an object file, you can hard paste your content, or generate them from variables. When auto generated, you have to build the structure on how you can add things.

For, instance, you can create the below constant, herein you can add "variables". The location can be the $path variable, the lastmod, can be the $modify_date, so when you modify a page content, and someone queries the sitemap.xml, the modified date will de displayed here.

Those are existing variables that you can query for this file. What about none existing variables, such as changefreq and priority? Well you can create variables , and set where those variables need to be displayed.

When you click Create variables "" you can select the name, the type of input required, and also which other module needs this setting. Example:

nameinput typeinput valuesshort_descriptionlong_description
prioritynumberThe priority of this URL relative to other URLs on your site. Valid values range from 0.0 to 1.0. This value does not affect how your pages are compared to pages on other sites—it only lets the search engines know which pages you deem most important for the crawlers.The default priority of a page is 0.5.

Please note that the priority you assign to a page is not likely to influence the position of your URLs in a search engine's result pages. Search engines may use this information when selecting between URLs on the same site, so you can use this tag to increase the likelihood that your most important pages are present in a search index.

Also, please note that assigning a high priority to all of the URLs on your site is not likely to help you. Since the priority is relative, it is only used to select between URLs on your site.
lastmoddateThe date of last modification of the page. This date should be in W3C Datetime format. This format allows you to omit the time portion, if desired, and use YYYY-MM-DD.Note that the date must be set to the date the linked page was last modified, not when the sitemap is generated.

Note also that this tag is separate from the If-Modified-Since (304) header the server can return, and search engines may use the information from both sources differently.
changefreqselectalways,hourly,daily,weekly,monthly,yearly,neverHow frequently the page is likely to change. This value provides general information to search engines and may not correlate exactly to how often they crawl the page
<?xml version="1.0" encoding="UTF-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

   <url>

      <loc>http://www.example.com/</loc>

      <lastmod>2005-01-01</lastmod>

      <changefreq>monthly</changefreq>

      <priority>0.8</priority>

   </url>

</urlset>

from https://sitemaps.org/protocol.html

security.txt

Example:

Contact: mailto:security@eurobytes.eu
Expires: 2022-07-30T19:00:00.000Z
Encryption: https://eurobytes.eu/.pgp
Acknowledgments: https://eurobytes.eu/hall-of-fame
Preferred-Languages: en
Canonical: https://eurobytes.eu/.well-known/security.txt
Policy: https://eurobytes.eu/security-policy
Hiring: https://eurobytes.eu/vacancies

https://securitytxt.org/

humanstxt.org

/* TEAM */
	Chef:
	Contact: hello [at] humanstxt.org
	Twitter: @{handle}
	From: {City, state, Country}


/* THANKS */

	EN Translator: {name}
	Twitter: @{handle}
	From: {City, state, Country}

/* SITE */
	Last update: YYYY/MM/DD
	Language: English / Dutch / German
	Doctype: HTML5
	IDE: Phpstorm, THE GIMP, draw.io, Firefox (Developer Edition)

https://humanstxt.org/

RSS Feed

You can create your XML structure, and fill it with your variables:

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">

<channel>
  <title>W3Schools Home Page</title>
  <link>https://www.w3schools.com</link>
  <description>Free web building tutorials</description>
  <item>
    <title>RSS Tutorial</title>
    <link>https://www.w3schools.com/xml/xml_rss.asp</link>
    <description>New RSS tutorial on W3Schools</description>
  </item>
  <item>
    <title>XML Tutorial</title>
    <link>https://www.w3schools.com/xml</link>
    <description>New XML tutorial on W3Schools</description>
  </item>
</channel>

</rss>

https://schemas.liquid-technologies.com/w3c/rss/2.0.1.9/?page=rss-2_0_1-rev9_xsd.html

https://www.w3schools.com/xml/xml_rss.asp

The EuroCMS Search Module

How

It queries the content table for what is live. And checks the table it links to. After that.

You can manage what it can and cannot search for.

You can enable/disable the following options,

  • file type

  • date

  • users(if logged in)

Search Engines

The default search engine, at the time of writing, is MariaDB. With the options to enable other search engines.

  • MariaDB

  • Solr

  • ...

DB structure

Check the content database table for published content, and queries them per file type.

search_iddomain_iduser_idgroup_idnameuser_lockstatus
111nullMariaDB1enabled
111nullSolr1disabled

The EuroCMS Settings Module

authorversiondate
Imri Palojadraft24-07-2022

The Setting modules allows components to store key value data in the database, securely.

The settings class allows to SET and GET values. It will auto detect the name and component type, and use them as a parameter for the DB query.

Only the Files module is allowed to access Files saved data.

Contemplate

  • Make this a generic named key value, with type and such?

The variables in EuroEditor, are saved as in object in the database, with the first value hard set.

Make this the "Value" module. So that every component can save any and all things in here. Not just settings items?

DB Structure

setting_iddomain_iduser_idgroup_iddescriptiontypecomponentcomponent_namekeyvalueuser_lockstatus
111settingsmodulesFilesSTORAGE_HANDLERLocalenabled
211settingsmodulesEuroEditorFORMATmarkdownenabled
311settingsfunctionIPInfoAPI_KEYzxcvasdfqwenabled
411settingsfunctionHetrixToolsAPI_KEYqwertyenabled
511settingslibrariesexiftoolINSTALLED_BINARYtrueenabled
611settingscoreSearchENGINESolrenabled
711settingsthemesSkeletonSKELETON_VERSION2.0.4enabled
811settingswidgetsNewUbuntuReleaseLATEST_VERSION22.04enabled
911variablemodulesEuroEditorUBUNTU_LTS_VERSION22.04
1011modulesFormsINPUTS
1111modulesapiDEFAULT_OUTPUTyaml
1211modulesapiYAML_REGEX{}:|>?<
1311

Permissions

settings_addThe ability to add a new settings data
setting_modifyThe ability to modify existing settings data
settings_deleteThe ability to delete existing settings data

The EuroCMS Socials Module

With this module you can manage your social media accounts. This will also give you the option to add Socials buttons to your website.

And will also allow you to automatically post to Social website automatically.

db structure

social_iddomain_iduser_idgroup_idnametokenshare_urliconprimary_coloruser_lockstatus
111nullTwitter{ApiToken}https://...#{hex value}1enabled
211nulllinkedIN{ApiToken}https://...fb#{hex value}nulldisabled
311null{ApiToken}https://...nullenabled
411null{ApiToken}https://...nullenabled

Manage Social accounts

Post, edit and review the things you post on social media, using your account(s).

Twitter

Example curl code:

curl -XPOST
  --url 'https://api.twitter.com/1.1/statuses/update.json?status=hello'
  --header 'authorization: OAuth
  oauth_consumer_key="oauth_customer_key",
  oauth_nonce="generated_oauth_nonce",
  oauth_signature="generated_oauth_signature",
  oauth_signature_method="HMAC-SHA1",
  oauth_timestamp="generated_timestamp",
  oauth_token="oauth_token",
  oauth_version="1.0"'

PHP Example

The below PHP code is a work in progress

The following is how I want to structure it

ns Twitter

class lookup:

  • function Tweet

  • function User

  • function Spaces

  • function blocks

  • function list

class Tweet:


<?php

namespace Twitter {

  const oauth_consumer_key = '';
  const oauth_nonce = '';
  const oauth_signature = '';
  const oauth_signature_method = '';
  const oauth_timestamp = '';
  const oauth_token = '';
  const oauth_version = '';

  const base_url = 'https://api.twitter.com/2';


  class TweetLookup {


    function __construct() {

    }

    function Single() {

    }

    function SingleUserContext() {

    }

    function Multiple() {

    }

  }

  class UserLookup {


    function __construct() {

    }

    function UserByID() {

    }

    function UserSByID() {

    }

    function UserByUsername() {

    }

    function UsersByUsername() {

    }

    function AuthenticaedUserLookup() {

    }
  }

  class likes {

    function __construct() {
    }

function LikeATweet() {
    }

    function LikedTweets() {
    }

    function LikingUsers() {
    }

    function UnlikeATweet() {
    }
  }
}

Links

List of links per social media account

Twitter

The EuroCMS Themes Module

Manage EuroCMS Themes.

authorrevisiondate
Imri Palojadesign20-05-2022

With the Themes module you can manage the following per website:

  • Favicon

  • Widgets

  • Menus

  • Design palettes

Lastly you can also modify themes. This relies on the options the Theme developer has implemented for modification.

DB structure

theme_iddomain_iduser_idgroup_idnametemplatesauthorCompanylicenseuser_lockstatus
1111EuroBytesvOne,vTwo,vThree,vFourImri PalojaEuroBytesGPL21enabled
211nullSkeletonSkeleton@usernameenabled
311W3schoolsStartup,Shop,...enabled

Permissions

The builtin permissions by the module

namedescriptioncoc?
themes_addThe ability to add themes
themes_removeThe ability to remove themes
themes_modifyThe ability to modify themes

The EuroCMS Trash Module

Every module can dump their Files and content here.

DB structure

trash_iddomain_iduser_idgroup_idnametabletable_nametable_iddatatrash_dateretentionuser_lockstatus
1111File.png {fancybox popup}filesfile_id2{DATAJSON}{epoch date}30d1
2111/policy-privacy - {fancybox popup}pagespage_id4{Previous Table Information}{epoch date}30d2
  • retention:  how long files are allowed to remain before being permanently deleted.

This setting is saved in the configure module.

Requested permission

configure:

item: trash

value: numeric(30days,30months,3years, disabled.)

Permissions

namedescriptionCoC
trash_addThe ability to add items to the trash
trash_deleteThe ability to delete items in the trash
trash_retentionThe ability to set a trash retention policy

The EuroCMS Updates Module

The update module allows you to manage updates.

  • Incremental updates

Download only the changed files. Git like feature: https://github.com/czproject/git-php

example: If you change a typo in a .php,.css,.js file, those files are the only ones that will be downloaded.

If you have a change in the permission.json file, the permission file will be read by ECMS, to updates the permission db table.

If you have a change in the {Files,Users}.sql file, the database will be created again, by executing again the .sql file.

And all changes will be displayed to the user.

Also, the changelog.json will be read, to display what changes are they talking about.

Use https://www.php.net/manual/en/function.xdiff-file-patch.php ?

  • Full Updates

Download the complete application update.

db structure

The updates database structure.

update_iddomain_iduser_idgroup_idcomponentnameupdatesseverityfuture_install_dateinstall_dateuser_lockstatus
1111modulesFiles1security20-05-2022 00:00:0020-05-2022 00:00:001Installed
2111modulesUsers1criticalnullnullnullskipped
3111coreUploads1criticalnullnullnullskip
4111themesSkeleton1criticalnullnullnullskip
5111widgetsNAVmenu1bugnull20-05-2022 00:00:00nullInstalled

Permission

namedescription
updates_installThe ability to Install updates
updates_skipThe ability to skip updates.
updates_futureThe ability to future install updates.
updates_incrementalThe ability to update the changed files.
updates_fullThe ability to download the complete update package.
updates_changesThe ability to view the to be applied changes to ECMS.

The EuroCMS Accounts Module

AuthorRevision
Imri Palojadraft

The Accounts module manages all the accounts of an ECMS installation. EuroCMS applies the following control lists: RBAC, LBAC.

Domain-Role-Based Access Control List. DRBAC. Dr. Bac if you want to be cute about it.

  • Users

  • Groups

  • API Users

  • Roles

  • Permissions

Chain of Commands

A user in a lower chain of command cannot view and or delete anything of a user that is higher in the Chain Of Command.

No matter if the users has the, for example users_history permission, they cannot view the history of a user higher in command.

ACL FLOW

This is the step by step ACL FLOW:

  • Login

Credentials check

  • Roles

Getting the list of components the users has rights too.

This will be displayed in the admin navigation menu.

  • Permissions

When clicked on, for example, the link for the Users module, we will check for the specific permissions this logged in users has: (users_add,users_delete).

Users

The EuroCMS users.

There can only be one Owner user. This user is the owner of the entire EuroCMS installation. The admins are the next in command in terms of power. Although they can be admin of a website and or websites, they don't have these power by default. The owner users has no restrictions. It's advised, even if you have only one domain, to create an admin account with all needed permissions to work, and never use the Owner user.

user_idgroup_iddomain_iddnamefnamelnameunamepwordemailprofile_picrolereg_dateact_dateauth_methodstimezonecocstatus
111jdoeJohndoejohn{hash}john@doe.nl{URL}Owner{epoch_date}{epoch_date}credsEurope/Amsterdam1active
211,2janeJanedoeJane{hash}jane@doe.nlfile_id:6admin{epoch_date}{epoch_date}creds,email,telegramMars/Marineris2inactive
311jackJackdoeJack{hash}jack@doe.nlEdiThors{epoch_date}{epoch_date}telegramMars/Anseris3banned
412Johndoejohn{hash}john@doe.nladmin{epoch_date}{epoch_date}emailEurope/Amsterdam2active
512JanedoeJane{hash}jane@doe.nlEdiThors{epoch_date}{epoch_date}credsEurope/Amsterdam3active
612JaguesdoeJagues{hash}jag@doe.nlcontributor{epoch_date}{epoch_date}credsEurope/Amsterdam4active
712ECLIecliecli{hash}ecli@ecms.nlecli{epoch_date}{epoch_date}credsEurope/Amsterdam4active

Handle the IP blocking via the content module? IP blocking the /login page?

Contemplate if it's still useful to enable IP blocking per users if the /login page is already blocked via content.

Let's paint a scenario. A user is out of office/on holiday/at a meeting in a restaurant, they need him ASAP, to fix things. The /login page is IP blocked with the Office IP.

So, you connect to the Office VPN, and connect to the /login page. No need for the office.

You can implemented a wide variety of security for this, it's just how secure you want it. The current security implementation makes it highly secure.

After user feedback, with the v1, we will see if the demand for further security implementation is wanted.

To he honest, I'll probably want to implement all of the security implementations you can think of. To make it a highly interesting products for companies/governments/..., with high security demands.

Groups

The EuroCMS groups.

group_iddomain_iduser_idnamepretty_namepwordemailroleusers_idsuser_lockstatus
111edevECMS Developers{hash}edev@eurobytes.euEdiThors3,51enabled
211administratorsAdmin{hash}admins@eurobytes.euAdminStars21enabled

Roles

A role can have preset R/W settings for a specific ECMS components.

role_iddomain_iduser_idgroup_idnameshort_descriptionmodulespermissions_idHierarchy/ChainOfCommand?user_lockstatus
1111ownerThe owner of this EuroCMS installationallall11enabled
2111EdiThorsThe editor rolesusers,editor,files,analytics,widgets1,2,3,5,62nullenabled
3111AdminStarsThe domain administrator usersusers,editor,files,analytics,widgets1,2,3,4,53nullenabled
4111ecliThe ECLI usersupdates,maintenance1,2,3,4,52nullenabled

Permissions

The permissions/features are the features that the module has made available.

SELECT * FROM permissions WHERE component_name = 'users' AND permission_id in (1,2,3,5,6);
permission_iddomain_iduser_idgroup_idcomponent_typecomponent_namepermission_nameshort_descriptionuser_lockstatus
1111moduleusersusers_addThe ability to add usersnullenabled
2111moduleusersusers_deleteThe ability to delete usersnullenabled
3111moduleusersusers_mfaThe ability to modify existing usersnullenabled
4111modulefilesusers_modifyThe ability to setup MFAnullenabled
5111modulefilesfiles_uploadThe ability to upload files.nullenabled
6111modulethemestheme_addThe ability to add themesnullenabled
7111modulecontentcontent_addThe ability to add contentnullenabled
8111modulecontentcontent_deleteThe ability to delete contentnullenabled
9111modulecontentcontent_modifyThe ability to modify existing contentnullenabled
10111modulecontentcontent_ipThe ability to IP protect a contentnullenabled
11111modulecontentcontent_ajaxThe ability to add AJAX contentnullenabled
12111modulecontentcontent_objectThe ability to add auto generated files from variables(robots.txt/sitemap.xml/contribute.json)nullenabled

Users module permissions list

namedescription.........
users_addThe ability to add users
users_deleteThe ability to delete users
users_modifyThe ability to modify users
users_mfaThe ability to setup MFA
users_historyDisplay the actions of users(the actions displayed in the analytics table)
users_info_permissionsDisplay the users permission list.
users_rolesManage users roles
users_permissionsManage roles permissions list

Access Control List

Think about using a PHP constant for this?

$acl_base = array(
	"components" => array()
);

// user logged in,
// Get the users permission...

$acl_add = array(
    "components" => array(
      "modules" => array(
        "Users" => array("users_add","users_delete"),
        "Files" => array()
      ),
      "themes" => array("W3schools"),
    )
);



$acl = array_merge($acl_base, $acl_add);

print_r($acl);

output of the above code:

Array
(
    [components] => Array
        (
            [modules] => Array
                (
                    [Users] => Array
                        (
                            [0] => users_add
                            [1] => users_delete
                        )

                    [Files] => Array
                        (
                        )

                )

            [themes] => Array
                (
                    [0] => W3schools
                )

        )

)

Reference

The EuroCMS Themes

authorversiondate
Imri Palojadraft23-07-2022

EuroCMS has a variety of themes available, which in turn also have a variety of template.

A theme is basically a css and js file, and the template is the (HTML) structuring of your website, may it be a parallax template, or a CV template.

Currently the default theme is Skeleton, based on the Skeleton.css.

W3schools has multiple, from w3schools.com, they have a long list of templates.

Design palettes

TODO: Find out how professional website designers name and structure their design, and incorporate that in ECMS

  1. Primary color

  2. Secondary color

  3. Light and dark variants

The css directory containts styling in the following categories

  • Grid

  • Base Styles

  • Typography

  • Links

  • Buttons

  • Forms

  • Lists

  • Code

  • Tables

  • Spacing

  • Utilities

  • Clearing

  • Media Queries

Coloring

- primary color
- secondary color
- accent-color

Borders

- border-style
- border-color
- border-radius
- border-imageg

Images

--

$_SERVER

For the theme builder, there are php constant available. Theses constant are usually everything in the $_SERVER. See https://www.php.net/manual/en/reserved.variables.server.php for a list of variables available.

Due note, that these change depending on your server configuration. Give it a proper read, so that you don't come across surprises.

browscap

Next, we also have browscap data in php constant available. The data is prefix, with browscap_ , this because, names likes browser and version are to generic.

There is not a builtin function to handle this. Reason is that, at the time of writing, there are 48 different browscap data, to write a function, to check if a `Firefox.css` file exists, 48 time, would severally impact the performance of EuroCMS. So, the Theme developer has the option to use and not use any of the data.

Here is a list of examples on how you can use the browscap data.

# Let's say you have specific css files per browser, you can use the `browscap_browser` constant, to create something like this.
$browser = constant('browscap_browser');
# Firefox

echo file_get_contents("css/$browser/$browser.css");
# example: css/Firefox/Firefox.css

# Or, if you have specific css code, for a specific version of a browser, you can do the following:
$browser_version = constant('browscap_version');
echo file_get_contents("css/$browser/$browser_version.css");
# example: css/Firefox/100.0.css

# You can also build an if statement.
# For example, if your theme does not support IE, you can build this:
if($browser == 'IE') {
	die("<p><strong>$browser</strong> is not supported!</p>");
}
# What this does is: If the browser is IE(Internet Explorer), exit the script with a warning message.


# IF you don't like "if" statements, you can also do the same as with the css code above, like so:

require_once "inc/$browser/$browser.php";
# example: inc/IE/IE.php
# In the $browser.php, any browser specific code can be set.


# Here are some full example, using multiple variables
$platform = constant('browscap_platform');
# Ubuntu

$renderingengine_name = constant('browscap_renderingengine_name');
# Gecko

# We are loading js, css and PHP code, specific to the platform, browser and browser version.
echo file_get_contents("css/$platform/$browser-$browser_version.css");
# example: css/Ubuntu/Firefox-100.0.css

echo file_get_contents("css/$platform/$renderingengine_name.css");
# example: css/Ubuntu/Gecko.css

echo file_get_contents("js/$platform/$browser-$browser_version.js");
# example: js/Ubuntu/Firefox-100.0.js


require "inc/$platform/$browser-$browser_version.php";
# example: inc/Ubuntu/Firefox-100.0.php


# Here is a boolean example:
if($ismobiledevice) {
	echo file_get_contents("css/ismobiledevice.css");
}

# You can also use the constants as css class name
# Or, generate specific js code using the constants


# Or you can generate CSS styling inline, like so:

echo ".$platform .$browser {color: #FFFFFF;}";
# example: .Ubuntu .Firefox {color: #FFFFFF;}


echo "<div class=\"$platform $browser\">Your OS and browser styling</div>"
# example: <div class="Ubuntu Firefox">Your OS and browser styling</div>

The browscap data contains string and boolean values. Please view http://browscap.org/ua-lookup for an example output of the data, and also check the wiki page, for detailed examples on the data https://github.com/browscap/browscap/wiki

Main characteristic

  • To extend the front end experience.

  • Depending on the main theme, it can be fully modifiable.

JS Package manger

  • NPM?

https://www.npmjs.com/package/api

  • YARN?

  • Parcel?

  • jamjs?

https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Package_management

Permissions

Think about this!

namedescription
theme_editor_design_palettesManage a design pallete of a website
theme_editor_add
theme_editor_modify
theme_editor_add_metadata
theme_editor_styles

Reference

The EuroCMS Skeleton Theme

This is based on the skeleton.css, from http://getskeleton.com.

What is Skeleton?

A dead simple, responsive boilerplate.

Styling?

  • Grid For Grid it provides: .container,.column,.columns {}
  • Base Styles
  • Typography
  • Links
  • Buttons
  • Forms
  • Lists
  • Code
  • Tables
  • Spacing
  • Utilities
  • Clearing
  • Media Queries

example metadata.json

{
  "Skeleton":{
    "author":"Dave Gamache <hello@davegamache.com> (http://davegamache.com/)",
    "title":"The EuroCMS Skeleton Theme",
    "company":"WelcomeLend",
    "description":"Skeleton is a dead-simple, responsive boilerplate to kickstart any responsive project.",
    "tags":"Skeleton,Responsive,Boilerplate",
    "home_page":"http://getskeleton.com/",
    "support":"https://github.com/dhg/Skeleton/issues",
    "version":"2.0.4",
    "license":"MIT",
    "accept_license":true,
    "favicon":"Skeleton.ico",
    "thumbnail":"img/Skeleton.thumbnail.png",
    "category":"Theme",
    "templates":{
      "Skeleton":"tmpl/Skeleton.Skeleton.tmpl.theme.php",
      "Parallax":"tmpl/Skeleton.Parallax.tmpl.theme.php"
    }
  }
}

Reference

  1. http://getskeleton.com

The EuroCMS W3schools Theme

Template from: https://www.w3schools.com/w3css/w3css_templates.asp - using the w3.css libray.

Example package json file

{
  "ecms":{
    "version":"0.0.1",
    "data":{
      "package":"W3schools",
      "component":"themes",
      "version":"1.0.1",
      "homepage":"https://packages.eurocms.eu/themes/W3schools",
      "description":"The EuroCMS W3schools Theme",
      "maintainers":{
        "current":"Imri Paloja <imri@packages.eurocms.eu>",
        "original":"Imri Paloja <imri@eurobytes.nl>"
      },
      "Installed-Size":"987654321",
      "Depends":{

      },
      "Provides":{
        "features":{
          "w3schools_add":"Add W3schools",
          "w3schools_remove":"Remove W3schools"
        },
        "ajax":{
          "DummyRefreshAjax":"Refresh page via ajax"
        },
        "planner":{
          "Refresh":"Refresh something"
        },
        "dashboards":{
          "view":"View W3schools From the dashboard"
        }
      },
      "update":{
        "version_location":{
          "GET":"https://packages.eurocms.eu/themes/W3schools/latest_version.txt",
          "dns":"themes.W3schools.packages.eurocms.eu"
        },
        "download":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.ecms",
        "changelog":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.changelog.txt",
        "validation":{
          "md5sum":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.ecms.md5sum",
          "sha1sum":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.ecms.sha1sum",
          "sha512sum":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.ecms.sha512sum",
          "gpg":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.ecms.gpg"
        },
        "license":{
          "GET":"https://packages.eurocms.eu/themes/W3schools/VERSION/W3schools-VERSION.license.txt",
          "accept_license":true
        }
      }
    }
  }
}

The EuroCMS Development Environment

authorversiondate
Imri Palojadraft06-08-2022

I use vagrant as a development environment, with NGINX, PHP and MariaDB installed.

Tools

And its dependencies.

I use PHPStorm to develop in, but you can use your own editor.

Steps

After the installation of vagrant, all you need to do is run vagrant up. This will deploy an Ubuntu server with all the needed software.

The Vagrantfile will install and configure all the needed web server software, in the virtual machine.

The host name defined in the NGINX configuration file, is local.eurocms.io. You can set up your host info in /etc/hosts.

192.168.56.20 &nbsp; local.eurocms.io

You can modify the variables in the Vagrantfile, to suit your needs.

hostnamelocal.eurocms.io
IP address192.168.56.20
PHP Version8.0
Time zoneEurope/Amsterdam

EuroCMS

To remember when developing for ECMS, is that on runtime the $_SERVER  array is properly filtered and put in a constant. So the server variables can be viewed via constants, like so: constant(HTTP_HOST);.

The Engine class has allot of ECMS system constant. Like path of libraries, modules Themes and such. Type in Engine:: in IDEs like PHPStorm will show a list with available constants.

Core

Core development steps.

Libraries

Libraries development steps.

Modules

Modules development steps

ActiveModule can have functions. Or can be used to include php file with necessary functions.

Themes

Themes development steps

Widgets

Widgets development steps

The EuroCMS Module Development

Base

A good basis is to download the Dummy module, which contains everything you need to get started with your first ECMS module: https://git.eurobytes.eu/EuroCMS/Dummy

git clone https://git.eurobytes.eu/EuroCMS/Dummy.git
cd Dummy/

After that open the directory with your Editor Or IDE of your choice.

Security

The EuroCMS Access Control structure

There are 2 Access Control structures availabe. 1 for Components and 1 for accounts. Logged in users and such.

The Components Access Control structure

Is for the EuroCMS components that want to access different types of components and or code codes

So, lets say for example that a disqus comment box widget, for the front end of the websites, wants to access the database. That is weird, because it uses JS and external data for the comments. So that is pretty fishy.

If that widget wants to query it database, it can only do so by using the database class, and every component is defined in such a way, that the database class, can autodetect, who is calling him.

If the query is not legit, or it has no permission to that database class, it will output a permission denied message.

If the widget has requested access to the database class, and the users installed said widget, and reviewed requested permission carefully, it will not have any problems.

But, if the widget makes a query, that it not request permission for, it will deny the access again.

Another example, if the Files module want to modify anything in the users db, that is not allowed. Unless permission have been granted to do so.

The Accounts Access Control structure

The components you have access to, are defined in roles, in the users table, your role can be editor, for example.

In the roles db table, their is a listing of components the editor role has access to.

And in the features db table, the component features you have access to.

For example, you are a user, that has the editor role, in the admin nav menu, are the components you have access to defined in the roles db table.

You click on the /users link, and then, the features db table is queried on which features you have access to. So, for example, if you have the users_add feature, you can add users. If that's all you have, that is all you'll get.

By default everything is denied.

The general flow of the EuroCMS Access Control structure is a followed:

  • Users

Check if the user exists in the specific domain

  • Roles

Users exists, and is logged in, now check the roles, then display the modules and widgets in the admin navigational menu.

  • Features

The user sees the admin dashboard, he clicks on the link. By default he only has read only view. So, no other 'button' is available to him.

So, when the /users link is clicked, it will check which features it is allowed to use in the users module. For example: add, delete modify features.

Users

The users db table structure, with only the relevant security rows displayed

user_idgroup_iddomain_idemailpwordroleip_allowMFA_methodtokenreg_dateact_datestatus
111imri@eurobytes.nlENCRYPTED_PWORDowner127.0.0.1emailSHA512{DATE}{DATE}enabled
211fyodor@dostoevsky.ruENCRYPTED_PWORDeditor127.0.0.1smsSHA512{DATE}{DATE}enabled
311franz@kafka.deENCRYPTED_PWORDeditor127.0.0.1questionsSHA512{DATE}{DATE}enabled

If the user is created, a temporary token is generated, which will be e-mailed to the users e-mail. For activation, they can add the token when they first login in.

enable: Location-based authentication

After that, they can choose to disable the second factor e-mail verification method.

Groups

The group db table structure

group_idgroup_iddomain_idnameemailshort_descriptionrolereg_dateact_datestatus
111adminsadmins@eurobytes.euThe adminsadmin{DATE}{DATE}enabled
211EdiThorseditors@eurobytes.euThe EdiThorseditor{DATE}{DATE}enabled
311themesfiles@eurobytes.euThe ThemesManthemes{DATE}{DATE}enabled

Domain Based

Also by default is the Domain based Access Control list. The Roles and permissions are set per domain name that is installed.

Role Based

db structure

role_iddomain_iduser_idgroup_idnameshort_descriptioncomponentsmodulesthemeswidgets
1111EditorThe EdiThorsmodules,widgets,themesadmin,users,editorSkeleton,W3schoolsNavMenu,NewUbuntuRelease

Feature Based

The db structure of all the features available. New features can be registered by the Modules, Themes and Widgets.

feature_iddomain_iduser_idgroup_idnameshort_descriptioncomponent_typecomponent_owner
1121users_addThe ability to add usersmoduleusers
2121users_deleteThe ability to delete usersmoduleusers
3121users_modifyThe ability to modify usersmoduleusers
4121users_mfaThe ability to add multy factor authenticaiton for usersmoduleusers
5121editor_writeThe ability to write contentmoduleEuroEditor
6121editor_deleteThe ability to delete contentmoduleEuroEditor
7121editor_modifyThe ability to modify contentmoduleEuroEditor
8121editor_publishThe ability to publish contentmoduleEuroEditor
9121themes_installThe ability to Install themesthemesSkeleton
10121themes_removeThe ability to remove themesthemesSkeleton
11121themes_modifyThe ability to modify themesthemesSkeleton

Reference

The EuroCMS Chain Of Command

authorversiondate
Imri Palojadraft24-07-2022

This is another security/Privacy features for ECMS users.

Scenarios

The following scenarios explain why this was needed.

  • user_history

Let's say a user with the "Editor" role has been giving the users_history permission. Where you can see the history of the user. But, what if the "Editor" user wants to see the history of the Owner and or Admin users history, so how do you stop/protect from that. Well, that's where I thought up Chain of Commands.

With CoC, If the "Editor" users wants to see the Owner/Admin users history, so someone that's higher in rank, it may have the history button, but it won't display anything.

Contemplate: Don't display the history button at all?

  • Owner logged in as admin

Say, for security purposes, the Owner user has created an admin account for himself, and giving himself the same admin rights as the rest of the admins. But, the actual Owner, wants to have elevated privileges over the rest of the admins. He wants to have the Owner CoC, which means the rest of the admins have limited say on the things that the Owner CoC user has applied.

As an Owner, you can modify the CoC for users.

EuroCMS Database Protection

authorversiondate
Imri Palojadraft20-06-2022

Here is what is done to protect the database from hackers!

Code Protection

Writing code in such a way that it protects itself from SQL injection and such.

Data

Reference

The EuroCMS Standards

Authorreleasedate
Imri PalojaConcept19-06-2022

Code

Here are the EuroCMS coding standards. There are a million and one way to structure PHP code. The one and only true requirement for writing working code, is writing it in the proper syntax.

The below mentioned standards are something I(Imri Paloja) invented.

Code wise, where possible, it tries to adhere to different coding standard: D.R.Y., MVC, PSR. The operative word being *tries*. Sometimes in practice you have to make little changes here and there to make things fit the design.

I try to prevent Redundant Code, Dead Code, Unreachable code, Duplicate code, Code bloat

In the future there will be coding standards for PHP, CSS, JS and so on.

Fill out these categories:

  • Indenting and Line Length

  • Control Structures

  • Function Calls

  • Class Definitions

  • Function Definitions

  • Arrays

  • Comments

Looking at https://en.wikipedia.org/wiki/PHPDoc for proper commenting. https://docs.phpdoc.org/3.0/guide/internals/project-management.html.

  • Including Code

  • PHP Code Tags

  • Header Comment Blocks

  • Example URLs

  • Naming Conventions

  • File Formats

  • E_STRICT-compatible code

  • Error Handling Guidelines

  • Best practices

  • Sample File (including Docblock Comment standards)

Structure

This is a rough explanation of the structure of the code and what they do.

Engine

The Engine class is the engine that powers EuroCMS. In the load.php, the Engine class resides. That does the loading of all the code, and the code that's needed for the content to load.

The module, widgets, theme components are all structured in an MVC like format. Here is a basic folder and file structure of the Files module:

  • controller/Files.mod.php

Contains the class ActiveModule. in this class, there resides functions needed by the Files module.

  • tmpl/Files.cont.php

This contains the html structure of the Files module.

  • css/Files.cont.css

This contains the needed styling for the Files module.

  • js/Files.js.cont.js|Files.bottom.cont.js

Files.js.cont.js will the loaded in the top(<head></head>) html tag.

Those 4 are the MVC component. The following are optional.

  • ajax/

If you have an Ajax requests that is needed, you can add your files here: Files.ajax.php. You need to properly register the ajax request.

  • docs/Files.docs.md,Files.docs.features.md

You can view the Files.docs.md file completely, or you can create multiple Files.docs.features.md files, which you can view from the feature in question from the fontend.

  • lang/Files.lang.en-US.php

The language header will be read from browser, and such the lang/ directory will check for all the language file that the browser requested.

If the requested file is not available it will fall back to en-US. or The only one available.

  • files/

For any files you may need. pdf, docs,images, whatever

  • handlers/

Handlers are handlers that can be handled in multiple ways.

In the context of the Files module, you way want to have the option to upload to the local server or WebDAV.

So, you have a Local Handler, and a WebDAV handler. In the settings you can switch from Local and WebDAV.

You would have two files, in PHP abstract: Files.handler.WebDAV.php and Files.handler.Local.php.

The Widgets, Modules, Themes all have the similar MVC-ish folder structures.

functions

The standards for the functions to be used where possible

  • return should always be a json

The code that accessed the function, should be left to handle the output.

classes

  • ACL check

Functions are to small to implement ACL checks, a PHP class should always have a ACL check. Preferably in the __construct()

Reference

The EuroCMS Installation Guide

authorversiondate
Imri Palojadraft30-05-2022

The dependencies for EuroCMS are:

  • NGINX(/Apache)

  • PHP

  • MariaDB

Ubuntu

Make sure you have a fresh and updated version of Ubuntu, before continuing:

# clean all redundant packages
apt clean all

# Refresh the repo data
apt update

# A full upgrade of the Ubuntu system
apt full-upgrade

NGINX Installation

The installation steps are from: https://nginx.org/en/linux_packages.html#Ubuntu. Follow the below steps on by one.

# Install NGINX dependencies

apt install curl gnupg2 ca-certificates lsb-release

# Add the NGINX repo
echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" > /etc/apt/sources.list.d/nginx.list

# Add and accept the NGINX repo key.
curl -s 'https://nginx.org/keys/nginx_signing.key' | apt-key add -

# Refresh our repos
apt update

# Install NGINX
apt install nginx

Depending in your own setup, you can add an NGINX configuration item, for EuroCMS.

Starting up NGINX

NGINX should be loaded by default, if not, please enable it:

systemctl enable --now nginx

PHP Installation

Install the latest supported version of PHP and its modules:

apt install php php-fpm php-common php-curl php-dev php-imagick php-mysql php-zip php-gd

Browscap module for PHP.

browscap is a PHP module we use for our analytics module. Without this, the analytics module will not function.

# Download the latest browscap module
wget 'https://browscap.org/stream?q=Full_PHP_BrowsCapINI' -O /etc/php/fpm/conf.d/browscap.ini

Enabling the module in the php.ini file. Add the following content to: /etc/php/fpm/php.ini

[browscap]
; http://php.net/browscap
browscap = /etc/php/fpm/conf.d/browscap.ini

Restart PHP

Restart PHP for the changes to take affect.

systemctl restart php-fpm

MariaDB installation

We will install MariaDB via the official repos. From: https://mariadb.org/download/

Dependencies

Install the required dependencies:

apt install software-properties-common dirmngr apt-transport-https

Repo Key

Add the MariaDB repo key:

sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'

Repo

Add the repo key to your Ubuntu server

sudo add-apt-repository 'deb [arch=amd64] https://mariadb.mirror.wearetriple.com/repo/10.11/ubuntu `lsb_release -cs` main'

Installing the MariaDB server

apt install mariadb-server

Enabling the MariaDB server

systemctl enable --now mariadb

Creating our EuroCMS database and users

Change the EuroCMS user(EuroCMS_usr) and the password(EuroCMS_pword) to whatever you like. Make sure to securely save your credentials. You need them latter when installing EuroCMS.

mysql -u root -e 'create database EuroCMS_db;'
mysql -u root -e "grant all privileges on EuroCMS_db.* TO 'EuroCMS_usr'@'%' identified by 'EuroCMS_pword';"
mysql -u root -e 'FLUSH PRIVILEGES;'

You can change the % in the query, to an IP address, so that the Database is IP protected.

Now restart MariaDB

systemctl restart mariadb

Finished

Access your website, and you will be redirect to the EuroCMS installer. please follow the steps mentioned in the Installer.

Configuration Guide

After installation is done, there are allot of optimization available to do.

  • File/folder permissions

Make sure the files and folders have the proper permissions and owners. This on some servers is not properly set, which can be a security issue.

Also, make sure you run everything in its own user, and not by the root user or such.

  • Advanced Caching

    • Web Server

    • PHP OPCache

    • MariaDB Query

    • Memory

  • Web server Security rule

You can deny certain ways of accessing the web server application. This will benefit the security.

  • Web Application Firewall

Setup a web application firewall via your server.