diff --git a/.htaccess b/.htaccess new file mode 100644 index 00000000..f38dbabc --- /dev/null +++ b/.htaccess @@ -0,0 +1,2 @@ +# Prevent access to .git, .github, and config.php +RedirectMatch 404 ^/(\.git|\.github|config\.php) \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..dcddde35 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,67 @@ +# Changelog + +This file documents all notable changes made to ITFlow. + +## [25.01] + +### Added / Changed +- Added support for saving cards in Stripe for automatic invoice payments. +- Page titles now display detailed information (e.g., page name, client selection, company name, ticket and invoice info) for easier multi-tab navigation. +- Reintroduced the new admin role-check for admin pages. +- Admin roles can now be archived. +- Debug mode now shows the current Git branch. +- The auto-acknowledgment email for email-parsed tickets now includes a guest link. +- Recurring tickets no longer require a contact. +- Stripe online payment setup now prompts you to set the income/expense account. +- New cron/CLI scripts have been moved to the `/scripts` subfolder — remember to update your cron configurations! +- Moved modal includes to `/modals` to tidy up the root directory. +- Moved most include files to `/includes` to improve directory structure. +- Moved guest pages to `/guest` for better organization. +- Renamed the include file `pagination.php` to `filter_footer.php`, as it is used in conjunction with `filter_header.php` for page filtering. +- Guest ticket feedback now shows the ticket prefix and number, not just the ID. +- Individual POST handler logic pages are no longer directly accessible. +- Added the ability to delete payments on the Payments and Client Payments pages. +- Implemented domain history tracking. +- Added Asset Interface Linking/Connections to show what interface is connected to which interface port of another asset. +- Added Force Recurring Ticket option in more locations, not just for recurring tickets. +- Implemented row spanning and centered devices that occupy multiple units in a rack. +- Added tooltips to main navigation badge counts to clarify what is being counted. +- Reduced max records per page from 500 to 100 to prevent performance issues. +- Updated several plugins: + - `stripe-php` from 10.5.0 to 16.4.0 + - `Inputmask` from 5.0.8 to 5.0.9 + - `DataTables` from 2.1.8 to 2.2.1 + - `pdfmake` from 0.2.8 to 0.2.18 + - `php-mime-mail-parser` to 9.0.1 + - `TinyMCE` from 7.5.1 to 7.6.1 +- Removed unused libraries from the vendor folder and moved Stripe to the plugins folder, eliminating the vendor folder. +- Merged the MFA TOTP functionality files `base32static.php` and `rfc6238.php` into a single file (`totp`) and moved it to the plugins folder. +- No longer need to pass the DB connection (`$mysqli`) to the `addToMailQueue` function. +- Disabled HTML Purifier caching. +- Replaced the `nullable_htmlentities` function with `htmlspecialchars`. +- Updated filter variable naming. +- Implemented other minor UI updates, performance optimizations, and directory cleanups. + +### Fixed +- Fixed an issue where the ticket edit modal didn't show multi-client or no-client projects. +- Fixed asset interface losing DHCP settings. +- Fixed a 500 error when creating or editing recurring expenses due to an incorrect variable name. +- Fixed tickets created via the portal/email not being marked as billable. +- Fixed issues with editing recurring expenses. +- Resolved a regression where the TinyMCE editor didn’t display when adding or editing ticket templates. +- Fixed a TinyMCE license issue. + +### Removed / Deprecated +- Deprecated the cron scripts in the root directory. Cron jobs should now use the ones in the `/scripts` subfolder, which no longer require a cron key and must be run via CLI. + +### BREAKING CHANGES +- The client portal has been moved from `/portal` to `/client`: + - Links in previous emails will be broken. + - The Azure Entra ID SSO Redirect URI needs to be updated to `/client`. + - You may need to update other links (e.g., website, support page). +- Guest links have been moved from `/` to `/guest`. Previous links will be broken. + +## [24.12] + +### Added / Changed +- Introduced versioned releases for the first time! \ No newline at end of file diff --git a/README.md b/README.md index 6c1791cc..4863620d 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,10 @@ [![Contributors][contributors-shield]][contributors-url] [![Stargazers][stars-shield]][stars-url] -[![Issues][issues-shield]][issues-url] [![Commits][commit-shield]][commit-url] [![GPL License][license-shield]][license-url] -
-

ITFlow

@@ -47,43 +42,26 @@ ### The Problem -- You're a busy MSP with 101 things to do. -- Information about your clients is unorganised and unstructured: scattered in random tickets or folders - when you do eventually find it, it's out of date. -- For some issues, you spend longer looking for the relevant documentation than actually working the ticket. +- You're a small but busy managed service provider with 101 things to do. Information about your clients is unorganised, unstructured and outdated. +- For some work, you seem to spend longer looking for the relevant documentation than actually working on the issue/project. - On top of the technical day to day, you also have to take care of the financial side of the business - consistent pricing, quotes/invoicing, and accounting. ### The Solution: ITFlow -- ITFlow consolidates common MSP needs (IT Documentation, ticketing and billing) into one system - -### In Beta -* This project is in beta with many ongoing changes. Updates may unintentionally introduce bugs/security issues. Writing functional, secure code is very difficult. -* Whilst we are confident the code is safe, nothing in life is 100% safe or risk-free. Use your best judgement before deciding to store highly confidential information in ITFlow. -* We are hoping to have a stable 1.0 release by early 2025. +- ITFlow consolidates common MSP needs (documentation, ticketing and billing) into one unified system. ## Getting Started -ITFlow is self-hosted. There is a full installation guide in the [docs](https://docs.itflow.org/installation). +### Self Hosting +- The best installation method is to use the [install script](https://docs.itflow.org/installation_script) on Ubuntu/Debian. A video walk through is available [here](https://www.youtube.com/watch?v=kKz9NOU_1XE). +``` + wget -O itflow_install.sh https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh + bash itflow_install.sh +``` +- Other manual installation methods are available in the [docs](https://docs.itflow.org/installation). - - -### Installation via Script (Recommended Method) - - **Requirements** - - Clean Install of Debian 12 or Ubuntu 22.04 - - A public IP Address - - Ports 80 (HTTP) and 443 (HTTPS) TCP accessible from the outside in - - A Fully Qualified Domain Name pointing to the public IP Address – example itflow.example.com - - **Process** - - Login as root - - Download & run install script - ``` - wget -O itflow_install.sh https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh - bash itflow_install.sh - ``` - - Follow Instructions & navigate to setup URL shown - - Leave us feedback in the [forum](https://forum.itflow.org/d/11-road-map) +### Managed Hosting +- If you'd prefer, we can [host ITFlow for you](https://services.itflow.org/hosting.php). ## Key Features @@ -95,14 +73,7 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// ## Roadmap / Future to-do -* Comprehensive API to allow custom third party integration -* CalDAV to integrate with 3rd party calendars -* CardDAV to integrate with 3rd party Address books -* Recent caller toast alerts to click and bring up the clients account right away -* FIDO2 WebAuthn Support for passwordless auth (TPM Fingerprint), (USB Hardware keys such as Yubikey) - -See the [forum](https://forum.itflow.org/t/added-to-roadmap) and the [open issues](https://github.com/itflow-org/itflow/issues) for a full list of proposed features & known issues. - +We track the implementation of confirmed features and bugs via [TaskFlow](https://tasks.dev.itflow.org/tasks.php). Use the [forum](https://forum.itflow.org) to request features or raise bug reports. ## Support & Contributions @@ -111,7 +82,7 @@ See the [forum](https://forum.itflow.org/t/added-to-roadmap) and the [open issue For help using ITFlow, bugs, feature requests, and general ideas / discussions please use the community [forum](https://forum.itflow.org). ### Contributing -If you want to improve ITFlow, feel free to fork the repo and create a pull request, but make sure to discuss significant changes or new features with fellow contributors on the forum first. This helps ensure that your contributions are aligned with project goals, and saves time for everyone. All contributions should follow our [code standards](https://docs.itflow.org/code_standards). +If you want to improve ITFlow, feel free to fork the repo and create a pull reques. Make sure to discuss significant changes or new features with fellow contributors on the forum first. This helps ensure that your contributions are aligned with project goals, and saves time for everyone. All contributions should follow our [code standards](https://docs.itflow.org/code_standards). See the [contributing guide](https://docs.itflow.org/contribute). #### Contributors @@ -122,13 +93,14 @@ If you want to improve ITFlow, feel free to fork the repo and create a pull requ We’re incredibly grateful to the organizations and individuals who support the project - a big thank you to: - CompuMatter - F1 for HELP -- JetBrains - ## License - ITFlow is distributed "as is" under the GPL License, WITHOUT WARRANTY OF ANY KIND. See [`LICENSE`](https://github.com/itflow-org/itflow/blob/master/LICENSE) for details. +## Security +* As of 2025, we now have a stable release of the project. +* Whilst we are confident in the safety of the code, no system is risk-free. Nearly all software has bugs. Use your best judgement before storing highly confidential information in ITFlow. +* If you have a security concern, privately report it [here](https://github.com/itflow-org/itflow/security/policy). diff --git a/SECURITY.md b/SECURITY.md index f374eeac..bd6ba7fd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,25 +1,21 @@ # Security Policy -## **Please do NOT report security concerns/vulnerabilities publicly (Github issues/forum)** +## **Please do NOT report security concerns/vulnerabilities publicly (Issues/forum)** ---- +**We take security seriously** -## In Beta - -ITFlow is currently in beta and is a work in progress. - -**We take security seriously.** Whilst we are confident the code is safe, nothing in life is 100% safe or risk-free. You should use your best judgment before entering confidential information into the app. - -We attempt to follow security best practices where possible, including [automated code scanning](https://sonarcloud.io/component_measures?id=itflow-org_itflow&metric=security_rating&view=list). - -[![Security](https://sonarcloud.io/api/project_badges/measure?project=itflow-org_itflow&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=itflow-org_itflow) +- Whilst we are confident in the safety of the code, no system is risk-free. Nearly all software has bugs. Use your best judgement before storing highly confidential information in ITFlow. +- We attempt to follow security best practices where possible, including [automated code scanning](https://sonarcloud.io/component_measures?id=itflow-org_itflow&metric=security_rating&view=list). +- [![Security](https://sonarcloud.io/api/project_badges/measure?project=itflow-org_itflow&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=itflow-org_itflow) ## Supported Versions +We operate a rolling release model. Any bug fixes will be released into latest version of ITFlow, so you must stay up-to-date. | Version | Supported | | ------- | ------------------ | -| Beta | :white_check_mark: | -| 1.0 | Yet to be released | +| Beta | :x: | +| 24.12 | :white_check_mark: | +| 25.1 | :white_check_mark: (When released) | ## Reporting a Vulnerability via GitHub Security Advisories diff --git a/accounts.php b/accounts.php index f23a0f7e..f5f972da 100644 --- a/accounts.php +++ b/accounts.php @@ -4,7 +4,7 @@ $sort = "account_name"; $order = "ASC"; -require_once "inc_all.php"; +require_once "includes/inc_all.php"; // Perms enforceUserPermission('module_financial'); @@ -109,18 +109,18 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- + - @@ -174,7 +174,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- + - + @@ -184,10 +184,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
- + - + @@ -127,14 +127,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- + - + @@ -295,11 +295,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
@@ -34,5 +34,5 @@ require_once "inc_all_admin.php";
- - close(); ITFlow release version + + Current DB Version + + Current Code Commit - Current DB Version - + Current Branch + @@ -748,5 +753,5 @@ $mysqli->close();
- + - - + + set('Cache.DefinitionImpl', null); // Disable cache by setting a non-existent directory or an invalid one $purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]); $purifier = new HTMLPurifier($purifier_config); @@ -74,4 +75,4 @@ if ($email_status == 0) { - diff --git a/admin_role.php b/admin_role.php index 241a116f..db315d07 100644 --- a/admin_role.php +++ b/admin_role.php @@ -4,7 +4,7 @@ $sort = "user_role_is_admin"; $order = "DESC"; -require_once "inc_all_admin.php"; +require_once "includes/inc_all_admin.php"; //Rebuild URL @@ -110,11 +110,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- - - - + + Archive + @@ -125,7 +124,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
@@ -73,5 +73,5 @@ require_once "inc_all_admin.php";
-
+

Company Details

-
- -
-
- -
- -
-
- -
-
- "> -
-
- -
- -
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- +
+ + +
- -
-
+ +
+
+ +
+
+ +
+ +
+
-
- -
-
- +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
-
- -
- -
-
- -
- -
-
- -
- - -
-
@@ -120,5 +120,5 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
@@ -249,4 +249,4 @@ require_once "inc_all_admin.php";
@@ -39,5 +39,5 @@ require_once "inc_all_admin.php";
-
@@ -102,5 +102,5 @@ require_once "inc_all_admin.php";
@@ -327,5 +327,5 @@ require_once "inc_all_admin.php"; -
@@ -78,5 +78,5 @@ require_once "inc_all_admin.php";
@@ -193,4 +193,4 @@ require_once "inc_all_admin.php";
@@ -12,9 +12,6 @@ require_once "inc_all_admin.php";
-
Currently, we only integrate with Stripe. Please see this forum post.
-
-
value="1" id="enableStripeSwitch"> @@ -25,7 +22,7 @@ require_once "inc_all_admin.php";
">
- +
@@ -35,7 +32,7 @@ require_once "inc_all_admin.php";
- +
@@ -45,7 +42,7 @@ require_once "inc_all_admin.php";
- +
@@ -140,6 +137,8 @@ require_once "inc_all_admin.php";
+
Currently, we only integrate with Stripe. Please see this forum post.
+

@@ -151,5 +150,5 @@ require_once "inc_all_admin.php";
+ +
+
+

Online Payment - Client info

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ClientStripe Customer IDStripe Payment IDAction
+ +
+ +
+ +
+ +
@@ -41,4 +41,4 @@ require_once "inc_all_admin.php";
@@ -54,5 +54,5 @@ require_once "inc_all_admin.php";
@@ -44,7 +44,7 @@ require_once "inc_all_admin.php";
- +
@@ -62,5 +62,5 @@ require_once "inc_all_admin.php";
@@ -38,5 +38,5 @@ require_once "inc_all_admin.php";
@@ -63,5 +63,5 @@ require_once "inc_all_admin.php";
@@ -82,5 +82,5 @@ require_once "inc_all_admin.php";
-
-
5 ) { - require "admin_ticket_status_edit_modal.php"; + require "modals/admin_ticket_status_edit_modal.php"; } } @@ -123,13 +123,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
- set('Cache.DefinitionImpl', null); // Disable cache by setting a non-existent directory or an invalid one $purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]); $purifier = new HTMLPurifier($purifier_config); @@ -124,7 +125,7 @@ $sql_task_templates = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE @@ -139,5 +140,5 @@ $sql_task_templates = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE - @@ -231,13 +231,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); - "; + $history_html .= "DateFieldBeforeAfter"; + while ($row = mysqli_fetch_array($history_sql)) { + // Fetch data from the query and create table rows + $history_html .= ""; + $history_html .= "" . htmlspecialchars(date('Y-m-d', strtotime($row['domain_history_modified_at']))) . ""; + $history_html .= "" . htmlspecialchars($row['domain_history_column']) . ""; + $history_html .= "" . htmlspecialchars($row['domain_history_old_value']) . ""; + $history_html .= "" . htmlspecialchars($row['domain_history_new_value']) . ""; + $history_html .= ""; + } + $history_html .= ""; + + // Return the HTML content to JavaScript + $response['history'] = $history_html; + echo json_encode($response); } @@ -306,10 +320,10 @@ if (isset($_GET['share_generate_link'])) { // Return URL if ($item_type == "Login") { - $url = "https://$config_base_url/guest_view_item.php?id=$share_id&key=$item_key&ek=$login_encryption_key"; + $url = "https://$config_base_url/guest/guest_view_item.php?id=$share_id&key=$item_key&ek=$login_encryption_key"; } else { - $url = "https://$config_base_url/guest_view_item.php?id=$share_id&key=$item_key"; + $url = "https://$config_base_url/guest/guest_view_item.php?id=$share_id&key=$item_key"; } $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); @@ -346,7 +360,7 @@ if (isset($_GET['share_generate_link'])) { ] ]; - addToMailQueue($mysqli, $data); + addToMailQueue($data); } diff --git a/base32static.php b/base32static.php deleted file mode 100644 index a59feaff..00000000 --- a/base32static.php +++ /dev/null @@ -1,96 +0,0 @@ -'0', 'B'=>'1', 'C'=>'2', 'D'=>'3', 'E'=>'4', 'F'=>'5', 'G'=>'6', 'H'=>'7', - 'I'=>'8', 'J'=>'9', 'K'=>'10', 'L'=>'11', 'M'=>'12', 'N'=>'13', 'O'=>'14', 'P'=>'15', - 'Q'=>'16', 'R'=>'17', 'S'=>'18', 'T'=>'19', 'U'=>'20', 'V'=>'21', 'W'=>'22', 'X'=>'23', - 'Y'=>'24', 'Z'=>'25', '2'=>'26', '3'=>'27', '4'=>'28', '5'=>'29', '6'=>'30', '7'=>'31' - ); - - /** - * Use padding false when encoding for urls - * - * @return base32 encoded string - * @author Bryan Ruiz - **/ - public static function encode($input, $padding = true) { - if (empty($input)) return ""; - - $input = str_split($input); - $binaryString = ""; - - for ($i = 0; $i < count($input); $i++) { - $binaryString .= str_pad(base_convert(ord($input[$i]), 10, 2), 8, '0', STR_PAD_LEFT); - } - - $fiveBitBinaryArray = str_split($binaryString, 5); - $base32 = ""; - $i=0; - - while($i < count($fiveBitBinaryArray)) { - $base32 .= self::$map[base_convert(str_pad($fiveBitBinaryArray[$i], 5, '0'), 2, 10)]; - $i++; - } - - if ($padding && ($x = strlen($binaryString) % 40) != 0) { - if ($x == 8) $base32 .= str_repeat(self::$map[32], 6); - else if ($x == 16) $base32 .= str_repeat(self::$map[32], 4); - else if ($x == 24) $base32 .= str_repeat(self::$map[32], 3); - else if ($x == 32) $base32 .= self::$map[32]; - } - - return $base32; - } - - public static function decode($input) { - if (empty($input)) return; - - $paddingCharCount = substr_count($input, self::$map[32]); - $allowedValues = array(6,4,3,1,0); - - if (!in_array($paddingCharCount, $allowedValues)) return false; - - for ($i=0; $i<4; $i++){ - if ($paddingCharCount == $allowedValues[$i] && - substr($input, -($allowedValues[$i])) != str_repeat(self::$map[32], $allowedValues[$i])) return false; - } - - $input = str_replace('=', '', $input); - $input = str_split($input); - $binaryString = ""; - - for ($i=0; $i < count($input); $i = $i+8) { - $x = ""; - - if (!in_array($input[$i], self::$map)) return false; - - for ($j=0; $j < 8; $j++) { - $x .= str_pad(base_convert(@self::$flippedMap[@$input[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT); - } - - $eightBits = str_split($x, 8); - - for ($z = 0; $z < count($eightBits); $z++) { - $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y:""; - } - } - - return $binaryString; - } -} diff --git a/blank.php b/blank.php index 2e83e0bf..b5cf1f1d 100644 --- a/blank.php +++ b/blank.php @@ -1,4 +1,4 @@ - +