EuroCMS Wiki page
| Author | Version | Date |
|---|---|---|
| Imri Paloja | 1 | 31-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
| Recommended | Minimum | Notes | |
|---|---|---|---|
| Linux | Latest Ubuntu LTS version | AlmaLinux/Rocky Linux. | Any Linux distro that can provide the below listed software requirements and their dependencies *should* do the trick. |
| Web-server | NGINX | Apache | I tested ECMS most with NGINX. Although Apache should work also. |
| PHP | 8.0+ | 8.0+ | See PHP requirement listed below. |
Linux Requirement
| name | component | reason |
|---|---|---|
| exiftool | libraries | Read metadata of uploaded files; also strip the metadata of images for security purposes. |
| trid | libraries | File validation during upload |
PHP Requirement
List of PHP Modules needed by ECMS. This needs to be updated.
| Name | Who use this | How is this going to be used? |
|---|---|---|
| browscap | analytics module | scrapping of user agent string, and save the data to a DB. |
| zlib | core | Management of archive files |
| curl | core | For the http client |
| openssl | various components | |
| session | core | Management of Session |
| exif | core | fallback if exiftool is not available. |
| json | core | management of json files |
| mysqlnd | core | |
| PDO | core | Mangement of mariaDB |
| Phar | core | |
| mysqli | core | |
| pdo_mysql | core | |
| gd | core | Management 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_id | domain_id | user_id | group_id | SESS_ID | REMOTE_ADDR | REAL_X_IP | SERVER_PROTOCOL | REQUEST_METHOD | start_time | user_agent | browser | browser_version | browser_type | browser_bits | browser_maker | renderingengine_name | renderingengine_version | platform | platform_version | platform_bits | platform_maker | device_name | device_type |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | null | null | {PHP SESS ID} | 127.0.0.1 | {REAL_X_IP} | HTTP/1.0 | GET | {time} | Firefox | 119.0 | Browser | 64 | Mozilla Foundation | Gecko | 119.0 | Ubuntu | 22.04 | 64 | Canonical Foundation | Linux Desktop | Desktop | |
| 1 | 1 | 1 | {PHP SESS ID} | 127.0.0.1 | {REAL_X_IP} | HTTP/2.0 | GET | {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.
| name | description | values | value_description | value_format | value_example |
|---|---|---|---|---|---|
| access_delete | delete something in the access log | $access_id | delete log entries depending on the access_id value. | csv | 50,51,52,53,54,55 |
Links
The EuroCMS Access Control List
| Author | Version |
|---|---|
| Imri Paloja | 1 |
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 toGET/POST?
DB Structure
| ajax_id | domain_id | user_id | group_id | name | path | component_type | component_name | http_methods | local_only | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | FileUpload | /Files/FileUpload | module | Files | GET | true | null | enabled |
| 2 | 1 | 1 | 1 | Refresh | /themes/W3schools/refresh | themes | W3schools | GET,POST | true | null | enabled |
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
-
Audit Your Data for Personally Identifiable Information (PII)
-
Turn on IP Anonymization.
-
Audit your Collection of Pseudonymous Identifiers (hashed Emails, User IDs)
-
Update your Privacy Policy.
-
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.
- Later on we will try to implement MaxMind IP database in EuroCMS: https://www.php.net/manual/en/book.geoip.php
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.
-
ipinfo_ip- Hide this from the developers? Privacy purposes? -
ipinfo_hostname -
ipinfo_city -
ipinfo_region -
ipinfo_country -
ipinfo_loc -
ipinfo_org -
ipinfo_postal -
ipinfo_timezone -
ipinfo_readme
| key | value |
|---|---|
| IP | IP ADRESS(Will be encrypted in the stable version) |
| hostname | The reverse ip of the hostname |
| city | City name |
| region | Region |
| country | Country short code |
| loc | Altitude, Longitude |
| org | ISP |
| postal | Postal code |
| timezone | Europe/Amsterdam |
| readme | https://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:
-
Please read Browser detection using the user agent for when you want to use this feature.
-
At the time of writing, whatismybrowser.com, states that there are
184.934.645user 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:
| Key | Value |
|---|---|
| parent | Firefox 100.0 |
| comment | Firefox 100.0 |
| browser | Firefox |
| browser_type | Browser |
| browser_bits | 64 |
| browser_maker | Mozilla Foundation |
| browser_modus | unknown |
| version | 100.0 |
| majorver | 100 |
| minorver | 0 |
| platform | Ubuntu |
| platform_version | unknown |
| platform_description | Ubuntu Linux |
| platform_bits | 64 |
| platform_maker | Canonical Foundation |
| alpha | false |
| beta | false |
| win16 | false |
| win32 | false |
| win64 | true |
| frames | true |
| iframes | true |
| tables | true |
| cookies | true |
| backgroundsounds | false |
| javascript | true |
| vbscript | false |
| javaapplets | true |
| activexcontrols | false |
| ismobiledevice | false |
| istablet | false |
| issyndicationreader | false |
| crawler | false |
| isfake | false |
| isanonymized | false |
| ismodified | false |
| cssversion | 3 |
| aolversion | 0 |
| device_name | Linux Desktop |
| device_maker | unknown |
| device_type | Desktop |
| device_pointing_method | mouse |
| device_code_name | Linux Desktop |
| device_brand_name | unknown |
| renderingengine_name | Gecko |
| renderingengine_version | 100.0 |
| renderingengine_description | For Firefox, Camino, K-Meleon, SeaMonkey, Netscape, and other Gecko-based browsers. |
| renderingengine_maker | Mozilla 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_id | domain_id | user_id | group_id | description | uname | api_key | permission_id | creation_date | exp_date | requests_limit | requests_limit_per | request_count | auth_methods | ip_deny | ip_allow | pword | timezone | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | John's key | john | {SHA512} | 1,2,3,4,5,6,7,8,9 | {creation_date} | {exp_date} | 1000 | day | 123 | pword,api_key | null | {CLIENT_IP} | {BCRYPT} | Europe/Amsterdam | enabled |
| 2 | 2 | 3 | 8 | JNE | null | {SHA512} | 1,2,3 | {creation_date} | null | 100 | week | 25 | api_key | null | null | null | null | enabled |
| 2 | 2 | 3 | 8 | BLD | null | {SHA512} | 9,8,7,6,5 | {creation_date} | null | null | null | 54673567 | api_key | all | CLIENT_IP | {BCRYPT} | Europe/Amsterdam | disabled |
- 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
- https://www.eurovps.com/blog/understanding-php-caching/
- https://www.rosehosting.com/blog/how-to-install-and-configure-php-opcache-on-ubuntu-20-04/
- https://ivan.reallusiondesign.com/enabling-query-cache-for-mariadb-mysql/
- https://mariadb.com/kb/en/query-cache/
The EuroCMS Components
| Author | Version |
|---|---|
| Imri Paloja | 1 |
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
- https://www.w3schools.com/php/php_cookies.asp
- https://www.php.net/manual/en/reserved.variables.cookies.php
- https://www.php.net/manual/en/function.setcookie.php
- https://www.php.net/manual/en/features.cookies.php
The EuroCMS Databases
| Author | Version | Date |
|---|---|---|
| Imri Paloja | 1 | 31-05-2022 |
The EuroCMS database structure
This is the default structure of the EuroCMS database tables.
| {tablename}_id | domain_id | user_id | group_id | ... | ... | ... | ... | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|
| 1 | [0-9] | [0-9] | [0-9] | 1 | enabled | ||||
| 2 | [0-9] | [0-9] | [0-9] | null | disabled | ||||
| 3 | [0-9] | [0-9] | [0-9] | null | enabled |
- {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
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
- https://www.php.net/manual/en/errorfunc.examples.php
- https://www.php.net/manual/en/function.error-log.php
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_id | domain_id | user_id | group_id | component_type | component_name | name | handler | description | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | core | handlers | Secrets | SQLite | Secrets are saved in SQLite | 1 | active |
| 1 | 1 | 1 | 1 | core | handlers | Session | File | Sessions are saved by the File handler | 9 | active |
| 1 | 1 | 1 | 1 | core | handlers | DataBase | MariaDB | DataBase is managed by MariaDB | 2 | active |
| 1 | 1 | 1 | 1 | core | handlers | Comment | DataBase | Comments are handled by the default DataBase handler | 2 | active |
| 1 | 1 | 1 | 1 | core | handlers | http | cURL | http request are handled by cURL | 2 | active |
| 1 | 1 | 1 | 1 | core | handlers | access | MariaDB | Access Logs are specifically saved in MariaDB | 44 | active |
| 1 | 1 | 1 | 1 | core | handlers | error | MariaDB | Error Logs are specifically saved in MariaDB | 4 | active |
| 1 | 1 | 1 | 1 | core | handlers | PHP | {PHP_VERSION} | The PHP handler is loaded based by the PHP_VERSION constant. e.g.: PHP.handler.8.0.php | 44 | active |
| 1 | 1 | 1 | 1 | core | handlers | cache | local | The local cache is handled locally. | 15 | active |
| 1 | 1 | 1 | 1 | core | handlers | auth | MariaDB | The user authentication is done by users that are saved in MariaDB. | 16 | active |
| 1 | 1 | 1 | 1 | core | handlers | Search | DataBase | The Search engine will search for things in the default DataBase | 17 | active |
| 1 | 1 | 1 | 1 | core | handlers | Notifications | DataBase | The notification handlers | 17 | active |
| 1 | 1 | 1 | 1 | modules | Files | Storage | local | Where to store the uploaded files. Available options: WebDAV, AWS S3, Google Storage. | 4 | active |
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
| name | description | value | value description |
|---|---|---|---|
| handler_register | Add a new handler | string $name, string $handler, string $description | The handler information |
| handler_remove | Remove an existing handler | string $handler_id | The handler ID |
| handler_modify | Modify an existing handler | string $handler_id, string $name, string $handler, string $description | The handler ID and information |
| handler_user_lock | lock a handler from being modified by other users | string $handler_id | The handler ID |
Links
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_id | domain_id | user_id | group_id | name | short_description | values |
|---|---|---|---|---|---|---|
| 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.
| name | description |
|---|---|
| header_add | The ability to add headers per domain |
| header_remove | The ability to remove headers per domain |
| header_modify | The ability to modify headers per domain |
db structure
| header_id | domain_id | user_id | group_id | name | values | description | user_lock | status |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | Content-Security-Policy | default-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 from | enabled | ||
| 2 | 1 | 1 | Strict-Transport-Security | max-age={number},includeSubDomains | HTTP 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 HTTP | enabled |
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
- https://owasp.org/www-project-secure-headers/
- https://www.php.net/manual/en/function.header
- https://infosec.mozilla.org/guidelines/web_security
The EuroCMS Login Controller
| author | date | status |
|---|---|---|
| Imri Paloja | 11-2023 | acceptance |
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_id | domain_id | user_id | login_start_time | login_end_time | ip | sess_id | auth_method_used | login_token | permissions | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | microtime(true) | 127.0.0.1 | {PHP SESS ID} | ldap | ECMS-{-SHA512SUM-} | 1,2,3,4,5,6 | active | |
| 2 | 2 | 4 | microtime(true) | 127.0.0.1 | {PHP SESS ID} | creds,email,telegram | ECMS-{-SHA512SUM-} | 1,2,3,4,5 | processing | |
| 3 | 2 | 54 | microtime(true) | 127.0.0.1 | {PHP SESS ID} | creds,email | ECMS-{-SHA512SUM-} | 1,2,3,4 | inactive | |
| 4 | 1 | 35 | microtime(true) | microtime(true) | 127.0.0.1 | {PHP SESS ID} | creds,telegram | ECMS-{-SHA512SUM-} | 1,2,3 | expired |
| 5 | 1 | 2 | microtime(true) | microtime(true) | 127.0.0.1 | {PHP SESS ID} | creds | ECMS-{-SHA512SUM-} | 1,2 | terminated |
| 6 | 1 | 6 | microtime(true) | microtime(true) | 127.0.0.1 | {PHP SESS ID} | creds,email,pword | ECMS-{-SHA512SUM-} | 1 | concluded |
- 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 isECMS-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.
| name | description | value | value description | value example |
|---|---|---|---|---|
| login_list | List all of the logged in users (In the current domain, and within its own change of command) | null | No value needed. It will list all of the logins in the current domain | null |
| 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_status | Set the status of the user in the login process. Available options are: active,processing,inactive,expired,terminated,concluded | |||
| login_get_status | Get 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 type | int | int | string | string(valid IP) | string | string | string | string | string |
| custom filtering | none | none | Numeric value with a dot. | validate_ip | alpha numeric value | csv output. | custom ECMS validator | csv | one of: active, processing, inactive, expired, terminated, concluded |
login_set_status
| name | $status |
|---|---|
| data type | string |
| custom filtering | String needs to be one of: active, processing, inactive, expired, terminated, concluded |
| expected value |
| expected value | description |
|---|---|
| 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. |
- 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 type | string |
| custom filtering | String 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_id | domain_id | user_id | group_id | to | send_date | from | subject | message | additional_headers | status | template | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | imri@eurobytes.eu | Test Message | LONGTEXT | Reply-to | EBS | |||||
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
- Register an URL with the Routes module
- Let core.metrics.php handle it.
- 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
- https://openmetrics.io/
- https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md
- https://github.com/OpenObservability/OpenMetrics/blob/main/proto/openmetrics_data_model.proto
- https://grafana.com/blog/2020/09/01/kubecon--cloudnativecon-eu-recap-what-you-need-to-know-about-openmetrics/
The EuroCMS Notification
View and manage notifications
Notifications db table
| notification_id | domain_id | user_id | group_id | component | name | severity | title | content | viewed |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | themes | Skeleton | CRITICAL | Missing file (test.xml) | long text | no |
| 2 | 1 | 1 | null | PHP? Engine? | Engine:URL | Security | SQL injection attempt by PHPSESSID: ABCDEFG | long text | no |
| 3 | 1 | 1 | null | analytics | NotFound | INFO | A visitor generated a 404 | ong text | no |
| 4 | 1 | 1 | null | core | Updates | Warning | 5 updates are available | long text | no |
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
- controller/
- Files/
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
- https://www.debian.org/doc/manuals/securing-debian-manual/deb-pack-sign.en.html
- https://www.debian.org/doc/manuals/maint-guide/checkit.en.html
- https://linuxhint.com/check-installed-package-debian-ubuntu/
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_id | domain_id | user_id | group_id | component | name | updates | severity | future_install_date | install_date | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | modules | Files | 1 | security | 20-05-2022 00:00:00 | 20-05-2022 00:00:00 | 1 | Installed |
| 2 | 1 | 1 | 1 | modules | Users | 1 | critical | null | null | null | skipped |
| 3 | 1 | 1 | 1 | core | Uploads | 1 | critical | null | null | null | Ignored |
| 4 | 1 | 1 | 1 | themes | Skeleton | 1 | critical | null | null | null | delayed |
| 5 | 1 | 1 | 1 | widgets | NAVmenu | 1 | bug | null | 20-05-2022 00:00:00 | null | Installed |
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
| Author | version |
|---|---|
| Imri Paloja | draft |
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
| cli | argument | permission name | csv(uname,fname,lname,pword,email,profile_pic,role,login_token,auth_methods,timezone,coc) |
| ecli | users | add_users | jd,John,Doe,PWORD,john@doe.nl,file_id,cli,null,creds,Europe/Amstedam,5 |
users_delete | csv of user_id
| cli | argument | parameter(permission name) | csv of user_id |
| ecli | users | add_delete | 1 |
...
...
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
-
Powerful, fast, flexible and customizable
-
Reads EXIF, GPS, IPTC, XMP, JFIF, MakerNotes, GeoTIFF, ICC Profile, Photoshop IRB, FlashPix, AFCP, ID3, Lyrics3 and more...
-
Writes EXIF, GPS, IPTC, XMP, JFIF, MakerNotes, GeoTIFF, ICC Profile, Photoshop IRB, AFCP and more...
-
Reads and writes maker notes of many digital cameras
-
Reads timed metadata (eg. GPS track) from MOV/MP4/M2TS/AVI videos
-
Numerous output formatting options (including tab-delimited, HTML, XML and JSON)
-
Multi-lingual output (cs, de, en, en-ca, en-gb, es, fi, fr, it, ja, ko, nl, pl, ru, sv, tr, zh-cn or zh-tw)
-
Geotags images from GPS track log files (with time drift correction!)
-
Generates track logs from geotagged images
-
Shifts date/time values to fix timestamps in images
-
Renames files and organizes in directories (by date or by any other meta information)
-
Extracts thumbnail images, preview images, and large JPEG images from RAW files
-
Copies meta information between files (even different-format files)
-
Reads/writes structured XMP information
-
Deletes meta information individually, in groups, or altogether
-
Sets the file modification date (and creation date in Mac and Windows) from EXIF information
-
Supports alternate language tags in XMP, PNG, ID3, Font, QuickTime, ICC Profile, MIE and MXF information
-
Processes entire directory trees
-
Creates text output file for each image file
-
Creates binary-format metadata-only (MIE, EXV) files for metadata backup
-
Automatically backs up original image when writing
-
Organizes output into groups
-
Conditionally processes files based on value of any meta information
-
Ability to add custom user-defined tags
-
Support for MWG (Metadata Working Group) recommendations
-
Recognizes thousands of different tags
-
Tested with images from thousands of different camera models
-
Advanced verbose and HTML-based hex dump outputs
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:
| name | description | CoC? |
|---|---|---|
| {ModuleName}_add | The ability to add things | 1 |
| {ModuleName}_remove | The ability to remove things | |
| {ModuleName}_modify | The 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.
| name | component | author | version | license | homepage | Size |
|---|---|---|---|---|---|---|
| Files | module | Imri Paloja | 1.0.0 | EuroCMS - Modules - Files | 500KB | |
| Skeleton | Themes | Imri Paloja | 1.0.0 | EuroCMS - Themes - Skeleton | 250KB | |
| NewUbuntuRelease | Widgets | Imri Paloja | 1.0.0 | EuroCMS - Widget - NewUbuntuRelease | 20KB | |
| Uploads | core | Imri Paloja | 1.0.0 | EuroCMS - Core - Uploads | 5KB | |
| exiftool | libraries | Imri Paloja | 1.0.1 | EuroCMS - Libraries - exiftool | 25KB |
Reference
The EuroCMS Analytics module
View analytics data
db structure
| SESSID | domain_id | user_id | group_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
| Author | Version |
|---|---|
| Imri Paloja | 1 |
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)
- tutorials/
- Skeleton/ (template name)
- Skeleton/ (theme name)
- 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)
- Amsterdam
- Europe/
- tours/
- band_page/ (template name) (template name)
- themes/
cache db structure
| cache_id | domain_id | user_id | group_id | component_type | component_name | name | user_lock | status | ||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | themes | skeleton | Skeleton | cached | |||
| 1 | 2 | 1 | 1 | core | content | /tutorials/how-to-do-a-thing | outdated |
-
cached: This is already cached
-
outdated: The database contains newer information.
Reference
The EuroCMS Configure Module
This module allows you to manage settings per domain.
DB structure
| configure_id | domain_id | user_id | group_id | https_redirect | keywords | author | title | theme | template | ip_deny | ip_allow | ... | ... | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | true | tutorials,editorals | author | EuroBytes - free tutorials | Skeleton | Skeleton | 127.0.0.1 | 127.0.0.1 | 1 | enable | ||
Permissions
| name | description | CoC |
|---|---|---|
| configure_modify | Modify 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_id | domain_id | user_id | group_id | cookie_name | cookie_description | category | cookie_id | cookie_domain | cookie_expires | httpOnly | path | samesite | secure | value |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | EuroBytes | Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. | Functioneel en analytisch | ebs-id | .eurobytes.eu | 2023-05-31T12:36:08.000Z | true | / | Lax | true | 686bf5f0-e6be-4e6c-98b7-9bd2e2747850 |
Reference
The EuroCMS Customers Module
| Author | version | date | Status |
|---|---|---|---|
| Imri Paloja | draft | 22-03-2023 | Contemplating |
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_id | domain_id | user_id | group_id | company_name | uname | fname | lname | pword | order | user_lock | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | [0-9] | [0-9] | [0-9] | Example Inc | jd | john@doe.eu | John | Doe | ${PWORD} | {JSON} | 1 | enabled |
| 2 | [0-9] | [0-9] | [0-9] | Jane Doe Photography | jdp | jane@doe.eu | Jane | Doe | ${PWORD} | {JSON} | 1 | enabled |
Permissions
The modules builtin permission list
| name | description | coc? |
|---|---|---|
| customer_add | The ability to add content | |
| customer_remove | The ability to remove content | |
| customer_modify | The ability to modify content | |
| customer_restore | The 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
| name | description | coc? |
|---|---|---|
| dashboard_add | The ability to add dashboards | |
| dashboard_delete | The ability to delete dashboards | |
| dashboard_modify | The 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_id | user_id | group_id | name | type | user_lock | status | ||||
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 5 | eurobytes.nl | website | 12,45 | enabled | ||||
| 2 | 1 | 4 | eurobytes.net | redirect | enabled | |||||
| 3 | 1 | 3 | api.eurobytes.nl | module | enabled | |||||
| 4 | 1 | 2 | eurobytes.com | alias | enabled |
Permissions
| name | description | coc? |
|---|---|---|
| domains_add | The ability to add domains | |
| domains_delete | The ability to delete domains | |
| domains_modify | The 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_id | domain_id | user_id | group_id | error_date | err_number | err_string | err_file | err_line | message | user_lock |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | ||||||
The EuroCMS Error Pages
You can modify error pages from EuroCMS.
db structure
| error_pages_id | domain_id | user_id | group_id | http_status | name | title | keywords | theme | template | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | 404 | Not found | The page could not be found | 404,not,found | enabled | |||
| 2 | 1 | 1 | null | 500 | Internal server error | There was an internal server error | 500,internal,server,error | enabled | |||
| 3 | 1 | 1 | null | 401 | Forbidden | You do not have the needed rights to see this. | 400,internal,server,error | 1,2 | enabled |
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
| name | description | coc? |
|---|---|---|
| error_pages_add | The ability to add error pages | |
| error_pages_delete | The ability to delete error pages | |
| error_pages_modify | The ability to modify error pages | |
| error_pages_theme | The 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
| name | description | ||
|---|---|---|---|
| euroeditor_add | The ability to add content into the content db table. | ||
| euroeditor_delete | The ability to delete content from the content db table. | ||
| euroeditor_modify | The ability to modify existing content in the content db table. | ||
| euroeditor_vars | The ability to create and modify variables and using them in different pages. | ||
| euroeditor_ip | The ability to IP protect a content in the content db table. | ||
| euroeditor_ajax | The ability to add AJAX content into the content db table. | ||
| euroeditor_object | The 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
| name | value | Delete |
|---|---|---|
| latest_lts_version | 22.04 | X |
| latest_lts_name | Jammy Jellyfish | X |
| ... | ... | X |
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.
| Attribute | Description |
|---|---|
| accesskey | Specifies a shortcut key to activate/focus an element |
| class | Specifies one or more classnames for an element (refers to a class in a style sheet) |
| contenteditable | Specifies whether the content of an element is editable or not |
| data-* | Used to store custom data private to the page or application |
| dir | Specifies the text direction for the content in an element |
| draggable | Specifies whether an element is draggable or not |
| hidden | Specifies that an element is not yet, or is no longer, relevant |
| id | Specifies a unique id for an element |
| lang | Specifies the language of the element's content |
| spellcheck | Specifies whether the element is to have its spelling and grammar checked or not |
| style | Specifies an inline CSS style for an element |
| tabindex | Specifies the tabbing order of an element |
| title | Specifies extra information about an element |
| translate | Specifies 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
-
Custom html tags: jsfiddle.net/blade1989/s81mr4gj
-
BIdirectional markdown/html converter: https://jsfiddle.net/blade1989/qjd3rcx8/49/
-
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_global_data
-
https://www.w3schools.com/jsref/met_document_getelementsbytagname.asp
-
https://www.w3schools.com/jsref/met_document_queryselectorall.asp
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.
| name | description | ... | ... | ... |
|---|---|---|---|---|
| files_add | The ability to upload files | |||
| files_delete | The ability to delete files | |||
| files_modify | The ability to modify files | |||
| files_metadata | The ability to read metadata from files | |||
| files_usage | The 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_id | domain_id | user_id | group_id | path | name | group | title | description | local_path | upload_date | type | mimetype | metadata | hash | thumbnail | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | /image/png/file.png | file.png | PNGs | File | The file.png | /engine/Files/Uploads/image/png/file.png | {date} | png | image/png | {exiftool json output} | {md5 hash} | /engine/Files/thumbnails/image/160-File.png | null | enabled |
| 1 | 1 | 1 | null | /image/jpg/file.jpg | file.jpg | JPGs | JFILE | The JFILE | /engine/Files/Uploads/image/jpg/file.jpg | {date} | jpg | image/jpg | {exiftool json output} | {md5 hash} | /engine/Files/thumbnails/jpeg/160-File.jpg | null | enabled |
| 1 | 1 | 1 | null | /image/jpg/file.pdf | file.pdf | PDFs | The pdf | /engine/Files/Uploads/application/pdf/file.pdf | {date} | application/pdf | {exiftool json output} | {md5 hash} | /engine/Files/thumbnails/pdf/160-pdf.jpg | null | enabled | ||
| 1 | 1 | 1 | null | /image/jpg/file.jpg | file.jpg | JPGs | JFILE | The JFILE | /engine/Files/Uploads/image/jpg/file.jpg | {date} | jpg | image/jpg | {exiftool json output} | {md5 hash} | /engine/Files/thumbnails/jpeg/160-File.jpg | null | enabled |
The EuroCMS Forms Module
| Author | Revision | date |
|---|---|---|
| Imri Paloja | design | 20-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_id | domain_id | user_id | group_id | form_name | form | user_lock | status |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | contact | {JsonBlob} | 1 | enabled |
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 ?
Reference
-
https://www.w3schools.com/html/html_form_attributes_form.asp
-
https://www.w3schools.com/html/html_form_elements.asp
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
- https://www.php.net/manual/en/configuration.changes.php
- https://www.php.net/manual/en/function.ini-get-all.php
The EuroCMS Installer Module
| Author | Version |
|---|---|
| Imri Paloja | 1 |
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:
-
ALL - where every file, during module installation is made read only, via file system, using
chattr. -
file.json, file.php: a comma seperated list of files that need to be read only.
-
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_id | domain_id | user_id | group_id | name | version | channel | author | description | license | accept_license | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | trid | 1.0.1 | stable | Marco Pontello | trid - file analyzer | GPL2 | true | enabled | ||
| 2 | 1 | 1 | exiftool | Phil Harvey | exiftool - metadata reader/writer | GPL2 | true | enabled |
- exiftool: you can use the system installed version, or download and install the
exiftoolversion yourself.
This is just in case hosting providers don't want to install extra packages in your system.
- trid: At the time of writing trid is not packages for a lot of Linux distros. Mainly Arch: https://pkgs.org/download/trid.
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
Reference
- https://en.wikipedia.org/wiki/Multi-factor_authentication
- https://www.loginradius.com/blog/identity/what-is-multi-factor-authentication/
- https://www.g2.com/categories/multi-factor-authentication-mfa
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_id | domain_id | user_id | group_id | name | short_description | redirect | content | clear | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | Session | defaults, clears the entire session data | /login | session | 1 | enabled | ||
| 2 | 2 | 1 | all | Clear 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
| name | description | coc? |
|---|---|---|
| notifications_add | The ability to add notifications | |
| notifications_remove | The ability to remove notifications | |
| notifications_modify | The 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. | ARTICLE | BLOG |
|---|---|---|
| 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_id | domain_id | user_id | group_id | page | author | post_date | name | title | local_path | lang | type | category | intro | content_image | content | keywords | Widgets | http_methods | csp | charset | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | / | John | {post_date} | 1 | en | page | index | This is our home page | /favicon.png | NavMenu | GET | utf-8 | published | |||||||
| 2 | 1 | 1 | /contact | Jane | en | page | contact | /favicon.png | NavMenu | GET | utf-8 | draft | ||||||||||
| 3 | 1 | 1 | 5 | /tutorials/howto-install-EuroCMS | en | page | index | /favicon.png | NavMenu | GET | utf-8 | waiting_for_review | ||||||||||
| 4 | 1 | 1 | 3 | en | page | /favicon.png | NavMenu | GET | utf-8 | denied | ||||||||||||
| en | page | /favicon.png | NavMenu | GET | utf-8 |
Permissions
The modules builtin permission list
| name | description | coc? |
|---|---|---|
| pages_add | The ability to add content | |
| pages_remove | The ability to remove content | |
| pages_modify | The ability to modify content | |
| pages_restore | The ability to restore content | |
| pages_user_lock | ||
The EuroCMS Planner
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 24-07-2022 |
Here is where you setup which code is allowed to be executed at an interval.
db structure
| plan_id | domain_id | user_id | group_id | component_type | component_name | name | description | tasks | time_interval | user_lock? | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | core | updates | Updates | Check for updates | Updates | every_minute | 1 | enabled |
| 2 | 1 | 1 | 1 | Maintenance | Execute various maintenance tasks | DiskUsage,CleanTmpFiles,FilePermCheck | every_hour | 1 | enabled | ||
| 3 | 1 | 1 | 1 | Validate | EuroCMS File validation; make sure no one has modified our files. | ECMSFValidation, | every_day | 1 | enabled | ||
| 4 | 1 | 1 | 1 | modules | Trash | Trash cleanup | Delete 30+ days files | Trash deletion | every_day | 1 | enabled |
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
| name | description | coc_id? |
|---|---|---|
| planner_add | The ability to add planner items | 1 |
| planner_remove | The ability to remove planner items | |
| planner_modify | The ability to modify existing planner items | |
| planner_logs | The 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_id | domain_id | user_id | group_id | fqdn | signature | validated | status_message | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | test.nl | {sha512} | true | 1 | enabled | |
| 2 | 1 | 1 | null | example.eu | {sha512} | false | Please complete the validation steps. | 1 | disabled |
ECMS Table structure
| repo_id | domain_id | user_id | group_id | name | components | pword | signature | https | HTTP_HOST | path | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | EuroCMS | Core,Libraries,Modules,Themes | {bcryptPassword} | {sha512} | true | repo.eurocms.eu | /repo.json | enabled |
| 2 | 1 | 1 | 1 | Themes | Themes | {bcryptPassword} | {sha512} | true | themes.eurobytes.eu | /repo.json | enabled |
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
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 06-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_id | domain_id | user_id | group_id | request | table | table_name | table_id | ip_deny | ip_allow | pword | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | /tutorials/how-to-eurocms | pages | page_id | 34 | null | null | {BCRYPT} | 1 | enabled |
| 2 | 1 | 1 | /api | modules | module_id | 54 | all | 127.0.0.2 | null | 3,5 | enabled | |
| 3 | 1 | 1 | /file/file.png | files | file_id | 5 | null | null | null | null | enabled | |
| 4 | 1 | 1 | /robots.txt | object | object_id | 50 | null | null | null | null | enabled | |
| 5 | 1 | 1 | /hackers.txt | object | object_id | 52 | null | null | null | null | enabled | |
| 6 | 1 | 1 | /sitemap.xml | object | object_id | 55 | null | null | null | null | enabled | |
| 7 | 1 | 1 | /Files/FileUpload | ajax | ajax_id | 2 | 127.0.0.1 | 127.0.0.2 | null | null | enabled | |
| 8 | 1 | 1 | /modules.json | files | file_id | 100 | null | null | null | null | disabled | |
| 9 | 1 | 1 | 1 | /api/users ??? contemplate on the whole row | api | api_id | 54 | all | 127.0.0.1,127.0.0.2 | {BCRYPT} | null | enabled |
Permissions
| name | description | ||
|---|---|---|---|
| route_add | The ability to add routes | ||
| route_delete | The ability to delete routes | ||
| route_modify | The ability to modify existing routes | ||
| route_ip | The ability to IP protect a routes | ||
| route_ajax | The ability to add AJAX routes | ||
| route_object | The 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:
| name | input type | input values | short_description | long_description |
|---|---|---|---|---|
| priority | number | The 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. | |
| lastmod | date | The 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. | |
| changefreq | select | always,hourly,daily,weekly,monthly,yearly,never | How 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
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)
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_id | domain_id | user_id | group_id | name | user_lock | status | |||
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | MariaDB | 1 | enabled | |||
| 1 | 1 | 1 | null | Solr | 1 | disabled |
The EuroCMS Settings Module
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 24-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_id | domain_id | user_id | group_id | description | type | component | component_name | key | value | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | settings | modules | Files | STORAGE_HANDLER | Local | enabled | |||
| 2 | 1 | 1 | settings | modules | EuroEditor | FORMAT | markdown | enabled | |||
| 3 | 1 | 1 | settings | function | IPInfo | API_KEY | zxcvasdfqw | enabled | |||
| 4 | 1 | 1 | settings | function | HetrixTools | API_KEY | qwerty | enabled | |||
| 5 | 1 | 1 | settings | libraries | exiftool | INSTALLED_BINARY | true | enabled | |||
| 6 | 1 | 1 | settings | core | Search | ENGINE | Solr | enabled | |||
| 7 | 1 | 1 | settings | themes | Skeleton | SKELETON_VERSION | 2.0.4 | enabled | |||
| 8 | 1 | 1 | settings | widgets | NewUbuntuRelease | LATEST_VERSION | 22.04 | enabled | |||
| 9 | 1 | 1 | variable | modules | EuroEditor | UBUNTU_LTS_VERSION | 22.04 | ||||
| 10 | 1 | 1 | modules | Forms | INPUTS | ||||||
| 11 | 1 | 1 | modules | api | DEFAULT_OUTPUT | yaml | |||||
| 12 | 1 | 1 | modules | api | YAML_REGEX | {}:|>?< | |||||
| 13 | 1 | 1 |
Permissions
| settings_add | The ability to add a new settings data | |
| setting_modify | The ability to modify existing settings data | |
| settings_delete | The 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_id | domain_id | user_id | group_id | name | token | share_url | icon | primary_color | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | {ApiToken} | https://... | #{hex value} | 1 | enabled | ||
| 2 | 1 | 1 | null | {ApiToken} | https://... | #{hex value} | null | disabled | ||
| 3 | 1 | 1 | null | {ApiToken} | https://... | null | enabled | |||
| 4 | 1 | 1 | null | {ApiToken} | https://... | null | enabled |
Manage Social accounts
Post, edit and review the things you post on social media, using your account(s).
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
The EuroCMS Themes Module
Manage EuroCMS Themes.
| author | revision | date |
|---|---|---|
| Imri Paloja | design | 20-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_id | domain_id | user_id | group_id | name | templates | author | Company | license | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | EuroBytes | vOne,vTwo,vThree,vFour | Imri Paloja | EuroBytes | GPL2 | 1 | enabled |
| 2 | 1 | 1 | null | Skeleton | Skeleton | @username | enabled | |||
| 3 | 1 | 1 | W3schools | Startup,Shop,... | enabled |
Permissions
The builtin permissions by the module
| name | description | coc? |
|---|---|---|
| themes_add | The ability to add themes | |
| themes_remove | The ability to remove themes | |
| themes_modify | The ability to modify themes | |
The EuroCMS Trash Module
Every module can dump their Files and content here.
DB structure
| trash_id | domain_id | user_id | group_id | name | table | table_name | table_id | data | trash_date | retention | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | File.png {fancybox popup} | files | file_id | 2 | {DATAJSON} | {epoch date} | 30d | 1 | |
| 2 | 1 | 1 | 1 | /policy-privacy - {fancybox popup} | pages | page_id | 4 | {Previous Table Information} | {epoch date} | 30d | 2 |
- 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
| name | description | CoC |
|---|---|---|
| trash_add | The ability to add items to the trash | |
| trash_delete | The ability to delete items in the trash | |
| trash_retention | The 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_id | domain_id | user_id | group_id | component | name | updates | severity | future_install_date | install_date | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | modules | Files | 1 | security | 20-05-2022 00:00:00 | 20-05-2022 00:00:00 | 1 | Installed |
| 2 | 1 | 1 | 1 | modules | Users | 1 | critical | null | null | null | skipped |
| 3 | 1 | 1 | 1 | core | Uploads | 1 | critical | null | null | null | skip |
| 4 | 1 | 1 | 1 | themes | Skeleton | 1 | critical | null | null | null | skip |
| 5 | 1 | 1 | 1 | widgets | NAVmenu | 1 | bug | null | 20-05-2022 00:00:00 | null | Installed |
Permission
| name | description | |
|---|---|---|
| updates_install | The ability to Install updates | |
| updates_skip | The ability to skip updates. | |
| updates_future | The ability to future install updates. | |
| updates_incremental | The ability to update the changed files. | |
| updates_full | The ability to download the complete update package. | |
| updates_changes | The ability to view the to be applied changes to ECMS. |
The EuroCMS Accounts Module
| Author | Revision |
|---|---|
| Imri Paloja | draft |
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_id | group_id | domain_id | dname | fname | lname | uname | pword | profile_pic | role | reg_date | act_date | auth_methods | timezone | coc | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | jdoe | John | doe | john | {hash} | john@doe.nl | {URL} | Owner | {epoch_date} | {epoch_date} | creds | Europe/Amsterdam | 1 | active |
| 2 | 1 | 1,2 | jane | Jane | doe | Jane | {hash} | jane@doe.nl | file_id:6 | admin | {epoch_date} | {epoch_date} | creds,email,telegram | Mars/Marineris | 2 | inactive |
| 3 | 1 | 1 | jack | Jack | doe | Jack | {hash} | jack@doe.nl | EdiThors | {epoch_date} | {epoch_date} | telegram | Mars/Anseris | 3 | banned | |
| 4 | 1 | 2 | John | doe | john | {hash} | john@doe.nl | admin | {epoch_date} | {epoch_date} | Europe/Amsterdam | 2 | active | |||
| 5 | 1 | 2 | Jane | doe | Jane | {hash} | jane@doe.nl | EdiThors | {epoch_date} | {epoch_date} | creds | Europe/Amsterdam | 3 | active | ||
| 6 | 1 | 2 | Jagues | doe | Jagues | {hash} | jag@doe.nl | contributor | {epoch_date} | {epoch_date} | creds | Europe/Amsterdam | 4 | active | ||
| 7 | 1 | 2 | ECLI | e | cli | ecli | {hash} | ecli@ecms.nl | ecli | {epoch_date} | {epoch_date} | creds | Europe/Amsterdam | 4 | active |
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_id | domain_id | user_id | name | pretty_name | pword | role | users_ids | user_lock | status | |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | edev | ECMS Developers | {hash} | edev@eurobytes.eu | EdiThors | 3,5 | 1 | enabled |
| 2 | 1 | 1 | administrators | Admin | {hash} | admins@eurobytes.eu | AdminStars | 2 | 1 | enabled |
Roles
A role can have preset R/W settings for a specific ECMS components.
| role_id | domain_id | user_id | group_id | name | short_description | modules | permissions_id | Hierarchy/ChainOfCommand? | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | owner | The owner of this EuroCMS installation | all | all | 1 | 1 | enabled |
| 2 | 1 | 1 | 1 | EdiThors | The editor roles | users,editor,files,analytics,widgets | 1,2,3,5,6 | 2 | null | enabled |
| 3 | 1 | 1 | 1 | AdminStars | The domain administrator users | users,editor,files,analytics,widgets | 1,2,3,4,5 | 3 | null | enabled |
| 4 | 1 | 1 | 1 | ecli | The ECLI users | updates,maintenance | 1,2,3,4,5 | 2 | null | enabled |
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_id | domain_id | user_id | group_id | component_type | component_name | permission_name | short_description | user_lock | status |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | module | users | users_add | The ability to add users | null | enabled |
| 2 | 1 | 1 | 1 | module | users | users_delete | The ability to delete users | null | enabled |
| 3 | 1 | 1 | 1 | module | users | users_mfa | The ability to modify existing users | null | enabled |
| 4 | 1 | 1 | 1 | module | files | users_modify | The ability to setup MFA | null | enabled |
| 5 | 1 | 1 | 1 | module | files | files_upload | The ability to upload files. | null | enabled |
| 6 | 1 | 1 | 1 | module | themes | theme_add | The ability to add themes | null | enabled |
| 7 | 1 | 1 | 1 | module | content | content_add | The ability to add content | null | enabled |
| 8 | 1 | 1 | 1 | module | content | content_delete | The ability to delete content | null | enabled |
| 9 | 1 | 1 | 1 | module | content | content_modify | The ability to modify existing content | null | enabled |
| 10 | 1 | 1 | 1 | module | content | content_ip | The ability to IP protect a content | null | enabled |
| 11 | 1 | 1 | 1 | module | content | content_ajax | The ability to add AJAX content | null | enabled |
| 12 | 1 | 1 | 1 | module | content | content_object | The ability to add auto generated files from variables(robots.txt/sitemap.xml/contribute.json) | null | enabled |
Users module permissions list
| name | description | ... | ... | ... |
|---|---|---|---|---|
| users_add | The ability to add users | |||
| users_delete | The ability to delete users | |||
| users_modify | The ability to modify users | |||
| users_mfa | The ability to setup MFA | |||
| users_history | Display the actions of users(the actions displayed in the analytics table) | |||
| users_info_permissions | Display the users permission list. | |||
| users_roles | Manage users roles | |||
| users_permissions | Manage 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
-
https://www.developer.com/open-source/creating-a-custom-acl-in-php/
-
https://www.codementor.io/@geggleto/php-psr-7-acl-package-d0g72j59c
-
https://www.openproject.org/docs/system-admin-guide/users-permissions/
The EuroCMS Themes
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 23-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
-
Primary color
-
Secondary color
-
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?
Permissions
Think about this!
| name | description |
|---|---|
| theme_editor_design_palettes | Manage 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
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
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 06-08-2022 |
I use vagrant as a development environment, with NGINX, PHP and MariaDB installed.
Tools
And its dependencies.
- IDE(PHPStorm)
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 local.eurocms.io
You can modify the variables in the Vagrantfile, to suit your needs.
| hostname | local.eurocms.io |
| IP address | 192.168.56.20 |
| PHP Version | 8.0 |
| Time zone | Europe/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_id | group_id | domain_id | pword | role | ip_allow | MFA_method | token | reg_date | act_date | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | imri@eurobytes.nl | ENCRYPTED_PWORD | owner | 127.0.0.1 | SHA512 | {DATE} | {DATE} | enabled | |
| 2 | 1 | 1 | fyodor@dostoevsky.ru | ENCRYPTED_PWORD | editor | 127.0.0.1 | sms | SHA512 | {DATE} | {DATE} | enabled |
| 3 | 1 | 1 | franz@kafka.de | ENCRYPTED_PWORD | editor | 127.0.0.1 | questions | SHA512 | {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_id | group_id | domain_id | name | short_description | role | reg_date | act_date | status | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | admins | admins@eurobytes.eu | The admins | admin | {DATE} | {DATE} | enabled |
| 2 | 1 | 1 | EdiThors | editors@eurobytes.eu | The EdiThors | editor | {DATE} | {DATE} | enabled |
| 3 | 1 | 1 | themes | files@eurobytes.eu | The ThemesMan | themes | {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_id | domain_id | user_id | group_id | name | short_description | components | modules | themes | widgets |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | Editor | The EdiThors | modules,widgets,themes | admin,users,editor | Skeleton,W3schools | NavMenu,NewUbuntuRelease |
Feature Based
The db structure of all the features available. New features can be registered by the Modules, Themes and Widgets.
| feature_id | domain_id | user_id | group_id | name | short_description | component_type | component_owner |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 2 | 1 | users_add | The ability to add users | module | users |
| 2 | 1 | 2 | 1 | users_delete | The ability to delete users | module | users |
| 3 | 1 | 2 | 1 | users_modify | The ability to modify users | module | users |
| 4 | 1 | 2 | 1 | users_mfa | The ability to add multy factor authenticaiton for users | module | users |
| 5 | 1 | 2 | 1 | editor_write | The ability to write content | module | EuroEditor |
| 6 | 1 | 2 | 1 | editor_delete | The ability to delete content | module | EuroEditor |
| 7 | 1 | 2 | 1 | editor_modify | The ability to modify content | module | EuroEditor |
| 8 | 1 | 2 | 1 | editor_publish | The ability to publish content | module | EuroEditor |
| 9 | 1 | 2 | 1 | themes_install | The ability to Install themes | themes | Skeleton |
| 10 | 1 | 2 | 1 | themes_remove | The ability to remove themes | themes | Skeleton |
| 11 | 1 | 2 | 1 | themes_modify | The ability to modify themes | themes | Skeleton |
Reference
- https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html
- https://csrc.nist.gov/CSRC/media/Publications/conference-paper/1992/10/13/role-based-access-controls/documents/ferraiolo-kuhn-92.pdf
- https://en.wikipedia.org/wiki/Role-based_access_control
- https://www.developer.com/open-source/creating-a-custom-acl-in-php/
- https://stackoverflow.com/a/4415733
- https://www.codementor.io/@geggleto/php-psr-7-acl-package-d0g72j59c
- https://www.openproject.org/docs/system-admin-guide/users-permissions/
The EuroCMS Chain Of Command
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 24-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
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 20-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
-
https://severalnines.com/blog/exploring-different-ways-encrypt-your-mariadb-data
-
https://webdock.io/en/docs/how-guides/security-guides/how-to-enable-encryption-mariadb
-
https://severalnines.com/database-blog/mariadb-server-database-encryption-basics
-
https://linuxhint.com/configure-database-level-encryption-mariadb/
-
https://www.php.net/manual/en/security.database.sql-injection.php
Reference
-
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
-
https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html
The EuroCMS Standards
| Author | release | date |
|---|---|---|
| Imri Paloja | Concept | 19-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
- https://pear.php.net/manual/en/standards.file.php
- https://developer.wordpress.org/coding-standards/wordpress-coding-standards/
- https://drupal.org/coding-standards
- https://www.php.net/manual/en/
The EuroCMS Installation Guide
| author | version | date |
|---|---|---|
| Imri Paloja | draft | 30-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.