From 4ac78418824e6e7e1622657b9bc1003ecab6bd74 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sat, 7 Oct 2023 15:51:58 +0100 Subject: [PATCH 01/20] Email parsing for all domains registered under a client - Add support for email parsing/contact creation for all domains registered under a client in the domains module, rather than just the client main website. - Additionally fix domain_created_at bug and move the new ticket auto-reply message to the email queue instead Future work: Make ticket parsing work with HTML emails (HTML emails break agent notifs) --- client_domains.php | 2 +- cron_ticket_email_parser.php | 55 +++++++++++---------- functions.php | 18 +++---- ticket.php | 94 +++++++++++++++++++----------------- 4 files changed, 86 insertions(+), 83 deletions(-) diff --git a/client_domains.php b/client_domains.php index d4610375..4d9f4a0c 100644 --- a/client_domains.php +++ b/client_domains.php @@ -72,6 +72,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $domain_webhost = intval($row['domain_webhost']); $domain_expire = nullable_htmlentities($row['domain_expire']); $domain_registrar_name = nullable_htmlentities($row['vendor_name']); + $domain_created_at = nullable_htmlentities($row['domain_created_at']); if (empty($domain_registrar_name)) { $domain_registrar_name = "-"; } @@ -82,7 +83,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); if ($row) { $domain_webhost_name = nullable_htmlentities($row['vendor_name']); } - $domain_created_at = nullable_htmlentities($row['domain_created_at']); ?> diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index c686c23f..993d91b7 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -94,9 +94,9 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date // Prep ticket details $message = nl2br($message); - $message = mysqli_real_escape_string($mysqli, "Email from: $contact_email at $date:-

$message"); + $message_escaped = mysqli_real_escape_string($mysqli, "Email from: $contact_email at $date:-

$message"); - mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$message', ticket_priority = 'Low', ticket_status = 'Pending-Assignment', ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_client_id = $client_id"); + mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$message_escaped', ticket_priority = 'Low', ticket_status = 'Pending-Assignment', ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_client_id = $client_id"); $id = mysqli_insert_id($mysqli); // Logging @@ -141,27 +141,16 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date // E-mail client notification that ticket has been created if ($config_ticket_client_general_notifications == 1) { - $email_subject = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"; - $email_body = "##- Please type your reply above this line -##

Hello, $contact_name

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"; + // Insert email into queue (first, escape vars) + $contact_email_escaped = sanitizeInput($contact_email); + $contact_name_escaped = sanitizeInput($contact_name); + $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); + $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); - $mail = sendSingleEmail( - $config_smtp_host, - $config_smtp_username, - $config_smtp_password, - $config_smtp_encryption, - $config_smtp_port, - $config_ticket_from_email, - $config_ticket_from_name, - $contact_email, - $contact_name, - $email_subject, - $email_body - ); + $subject_escaped = mysqli_escape_string($mysqli, "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"); + $body_escaped = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"); - if ($mail !== true) { - mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Mail', notification = 'Failed to send email to $contact_email'"); - mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Mail', log_action = 'Error', log_description = 'Failed to send email to $contact_email regarding $subject. $mail'"); - } + mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$contact_email_escaped', email_recipient_name = '$contact_name_escaped', email_from = '$config_ticket_from_email_escaped', email_from_name = '$config_ticket_from_name_escaped', email_subject = '$subject_escaped', email_content = '$body_escaped'"); } @@ -173,8 +162,10 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date $client_row = mysqli_fetch_array($client_sql); $client_name = sanitizeInput($client_row['client_name']); - $details = removeEmoji($message); - $email_subject = "ITFlow - New Ticket - $client_name: $subject"; + // TODO: Fix Emojis and HTML opening tags sometimes breaking this "forwarding" + $details = removeEmoji($message_escaped); + + $email_subject = mysqli_escape_string($mysqli, "ITFlow - New Ticket - $client_name: $subject"); $email_body = "Hello,

This is a notification that a new ticket has been raised in ITFlow.
Client: $client_name
Priority: Low (email parsed)
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$subject
$details"; mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$config_ticket_new_ticket_notification_email', email_recipient_name = 'ITFlow Agents', email_from = '$config_ticket_from_email', email_from_name = '$config_ticket_from_name', email_subject = '$email_subject', email_content = '$email_body'"); @@ -366,9 +357,17 @@ if ($emails) { $date = trim(mysqli_real_escape_string($mysqli, nullable_htmlentities(strip_tags($parser->getHeader('date'))))); $attachments = $parser->getAttachments(); + // Get the message content + // (first try HTML parsing, but switch to plain text if the email is empty/plain-text only) +// $message = $parser->getMessageBody('htmlEmbedded'); +// if (empty($message)) { +// echo "DEBUG: Switching to plain text parsing for this message ($subject)"; +// $message = $parser->getMessageBody('text'); +// } + + // TODO: Default to getting HTML and fallback to plaintext, but HTML emails seem to break the forward/agent notifications + $message = $parser->getMessageBody('text'); - // If below is enabled and up above is enabled text based emails get cut out - //$message = $parser->getMessageBody('htmlEmbedded'); // Check if we can identify a ticket number (in square brackets) if (preg_match("/\[$config_ticket_prefix\d+\]/", $subject, $ticket_number)) { @@ -407,14 +406,14 @@ if ($emails) { // Couldn't match this email to an existing ticket or an existing client contact // Checking to see if the sender domain matches a client website - $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM clients WHERE client_website = '$from_domain' LIMIT 1")); + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$from_domain' LIMIT 1")); - if ($row && $from_domain == $row['client_website']) { + if ($row && $from_domain == $row['domain_name']) { // We found a match - create a contact under this client and raise a ticket for them // Client details - $client_id = intval($row['client_id']); + $client_id = intval($row['domain_client_id']); // Contact details $password = password_hash(randomString(), PASSWORD_DEFAULT); diff --git a/functions.php b/functions.php index 11276006..5a047108 100644 --- a/functions.php +++ b/functions.php @@ -516,7 +516,7 @@ function sendSingleEmail($config_smtp_host, $config_smtp_username, $config_smtp_ $smtp_auth = true; } - try{ + try { // Mail Server Settings $mail->CharSet = "UTF-8"; // Specify UTF-8 charset to ensure symbols ($/£) load correctly $mail->SMTPDebug = 0; // No Debugging @@ -712,13 +712,13 @@ function shortenClient($client) { // Break into words. $words = explode(' ', trim($cleaned)); - + $shortened = ''; // If there's only one word. if (count($words) == 1) { $word = $words[0]; - + if (strlen($word) <= 3) { return strtoupper($word); } @@ -753,22 +753,22 @@ function roundToNearest15($time) { // Extract hours, minutes, and seconds from the matched time string list(, $hours, $minutes, $seconds) = $matches; - + // Convert everything to seconds for easier calculation $totalSeconds = ($hours * 3600) + ($minutes * 60) + $seconds; - + // Calculate the remainder when divided by 900 seconds (15 minutes) $remainder = $totalSeconds % 900; - + if ($remainder > 450) { // If remainder is more than 7.5 minutes (450 seconds), round up $totalSeconds += (900 - $remainder); } else { // Else round down $totalSeconds -= $remainder; } - + // Convert total seconds to decimal hours $decimalHours = $totalSeconds / 3600; - + // Return the decimal hours return number_format($decimalHours, 2); -} \ No newline at end of file +} diff --git a/ticket.php b/ticket.php index 8228e9fd..1ec5165d 100644 --- a/ticket.php +++ b/ticket.php @@ -327,15 +327,15 @@ if (isset($_GET['ticket_id'])) { - -
-
-
- - + +
+
+
+ + +
-
@@ -483,13 +483,13 @@ if (isset($_GET['ticket_id'])) {

Contact

- +
- + -
+
-
- $ticket_id ORDER BY ticket_id DESC LIMIT 1"; - $row = mysqli_fetch_assoc(mysqli_query($mysqli, $sql_prev_ticket)); + $prev_ticket_row = mysqli_fetch_assoc(mysqli_query($mysqli, $sql_prev_ticket)); - $prev_ticket_id = intval($row['ticket_id']); - $prev_ticket_subject = nullable_htmlentities($row['ticket_subject']); - $prev_ticket_status = nullable_htmlentities($row['ticket_status']); - ?> + if ($prev_ticket_row) { + $prev_ticket_id = intval($prev_ticket_row['ticket_id']); + $prev_ticket_subject = nullable_htmlentities($prev_ticket_row['ticket_subject']); + $prev_ticket_status = nullable_htmlentities($prev_ticket_row['ticket_status']); + ?> -
- Previous ticket: - -
-
- +
+
+ Previous ticket: + +
+
Status: - - - Status: - - -
- + + + + + +
+ + +
Add a Contact @@ -565,12 +569,12 @@ if (isset($_GET['ticket_id'])) { $sql_ticket_watchers = mysqli_query($mysqli, "SELECT * FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id ORDER BY watcher_email DESC"); while ($ticket_watcher_row = mysqli_fetch_array($sql_ticket_watchers)) { $ticket_watcher_email = nullable_htmlentities($ticket_watcher_row['watcher_email']); - ?> + ?>
- +
@@ -586,14 +590,14 @@ if (isset($_GET['ticket_id'])) {
Updated:
- + - + $ticket_closed_by_display = nullable_htmlentities($row['user_name']); + ?> +
Closed by:
@@ -601,7 +605,7 @@ if (isset($_GET['ticket_id'])) { Feedback:
- +
Total time worked: @@ -613,13 +617,13 @@ if (isset($_GET['ticket_id'])) {

Asset

- + - +
Add an Asset
- +
@@ -686,7 +690,7 @@ if (isset($_GET['ticket_id'])) { Ticket: $service_ticket_subject ($service_ticket_status)"; ?>

-
@@ -699,13 +703,13 @@ if (isset($_GET['ticket_id'])) {
- +
- +

Vendor

@@ -784,14 +788,14 @@ if (isset($_GET['ticket_id'])) { Invoice Ticket Close Ticket
- +
From 69eef8220d8f6cc1382ae64543b444b575e2bfe0 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sat, 7 Oct 2023 16:10:00 +0100 Subject: [PATCH 02/20] Ticket update behaviour - Default to internal update when contact email matches the agent email --- ticket.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ticket.php b/ticket.php index 8228e9fd..c53e89c7 100644 --- a/ticket.php +++ b/ticket.php @@ -326,8 +326,8 @@ if (isset($_GET['ticket_id'])) { - - + +
@@ -483,7 +483,7 @@ if (isset($_GET['ticket_id'])) {

Contact

- +
@@ -542,7 +542,7 @@ if (isset($_GET['ticket_id'])) {
- +
Add a Contact @@ -570,7 +570,7 @@ if (isset($_GET['ticket_id'])) {
- +
@@ -586,14 +586,14 @@ if (isset($_GET['ticket_id'])) {
Updated:
- + - +
Closed by:
@@ -601,7 +601,7 @@ if (isset($_GET['ticket_id'])) { Feedback:
- +
Total time worked: @@ -613,13 +613,13 @@ if (isset($_GET['ticket_id'])) {

Asset

- + - + - +
@@ -699,13 +699,13 @@ if (isset($_GET['ticket_id'])) {
- +
- +

Vendor

@@ -784,14 +784,14 @@ if (isset($_GET['ticket_id'])) { Invoice Ticket Close Ticket
- +
From 263382073d9e4aabcd99e93b0d28d7d3f5e304d2 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sat, 7 Oct 2023 20:42:48 +0100 Subject: [PATCH 03/20] Contact small edits - Adjust behaviour when selecting "Send user e-mail with login details?" (show reset link OR prompt user to change password if tech set one) - Email wording change (remove ITFlow reference and replace with MSP name) - Show contact PIN in the portal - Bump password min length to 8 (and enforce on tech side) - Bugfix undefined send_email value --- client_contact_edit_modal.php | 7 ++++--- portal/check_login.php | 1 + portal/profile.php | 3 ++- post/contact.php | 15 ++++++++++----- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/client_contact_edit_modal.php b/client_contact_edit_modal.php index 87c62fd9..9a46fc81 100644 --- a/client_contact_edit_modal.php +++ b/client_contact_edit_modal.php @@ -13,6 +13,7 @@ + @@ -198,7 +199,7 @@
- +
@@ -207,7 +208,7 @@
- +
@@ -252,4 +253,4 @@ - \ No newline at end of file + diff --git a/portal/check_login.php b/portal/check_login.php index c817b219..a90e3736 100644 --- a/portal/check_login.php +++ b/portal/check_login.php @@ -50,6 +50,7 @@ $session_contact_initials = initials($session_contact_name); $session_contact_title = sanitizeInput($contact['contact_title']); $session_contact_email = sanitizeInput($contact['contact_email']); $session_contact_photo = sanitizeInput($contact['contact_photo']); +$session_contact_pin = sanitizeInput($contact['contact_pin']); $session_contact_primary = intval($contact['contact_primary']); $session_contact_is_technical_contact = false; diff --git a/portal/profile.php b/portal/profile.php index faecd405..ca363b7d 100644 --- a/portal/profile.php +++ b/portal/profile.php @@ -13,6 +13,7 @@ require_once('inc_portal.php');

Name:

Email:

+

PIN:

Client:


Client Primary Contact:

@@ -35,7 +36,7 @@ require_once('inc_portal.php');
- + diff --git a/post/contact.php b/post/contact.php index cd9aa54d..39b157df 100644 --- a/post/contact.php +++ b/post/contact.php @@ -17,7 +17,7 @@ if (isset($_POST['add_contact'])) { // Set a random password $password_hash = password_hash(randomString(), PASSWORD_DEFAULT); } - + if (!file_exists("uploads/clients/$client_id")) { mkdir("uploads/clients/$client_id"); } @@ -68,6 +68,7 @@ if (isset($_POST['edit_contact'])) { require_once('post/contact_model.php'); $contact_id = intval($_POST['contact_id']); + $send_email = intval($_POST['send_email']); // Get Exisiting Contact Photo $sql = mysqli_query($mysqli,"SELECT contact_photo FROM contacts WHERE contact_id = $contact_id"); @@ -93,7 +94,7 @@ if (isset($_POST['edit_contact'])) { } // Send contact a welcome e-mail, if specified - if (isset($_POST['send_email']) && !empty($auth_method) && !empty($config_smtp_host)) { + if ($send_email && !empty($auth_method) && !empty($config_smtp_host)) { // Un-sanitizied used in body of email $contact_name = $_POST['name']; @@ -102,14 +103,18 @@ if (isset($_POST['edit_contact'])) { $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); + // Authentication info (azure, reset password, or tech-provided temporary password) + if ($auth_method == 'azure') { $password_info = "Login with your Microsoft (Azure AD) account."; + } elseif (empty($_POST['contact_password'])) { + $password_info = "Request a password reset at https://$config_base_url/portal/login_reset.php"; } else { - $password_info = $_POST['contact_password']; + $password_info = $_POST['contact_password'] . " -- Please change on first login"; } - $subject = sanitizeInput("Your new $session_company_name ITFlow account"); - $body = mysqli_real_escape_string($mysqli, "Hello, $contact_name

An ITFlow account has been set up for you.

Username: $email
Password: $password_info

Login URL: https://$config_base_url/portal/

~
$session_company_name
Support Department
$config_ticket_from_email"); + $subject = sanitizeInput("Your new $session_company_name support portal account"); + $body = mysqli_real_escape_string($mysqli, "Hello, $contact_name

$session_company_name has created a support portal account for you.

Username: $email
Password: $password_info

Login URL: https://$config_base_url/portal/

~
$session_company_name
Support Department
$config_ticket_from_email"); // Queue Mail mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$email', email_recipient_name = '$name', email_from = '$config_ticket_from_email_escaped', email_from_name = '$config_ticket_from_name_escaped', email_subject = '$subject', email_content = '$body'"); From dff0b689ce06264ab8cdee2c8bc9d64bf61ffc24 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sat, 7 Oct 2023 20:48:40 +0100 Subject: [PATCH 04/20] Add confirm to anonymise and archive --- client_contacts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_contacts.php b/client_contacts.php index b0dea328..3ead301d 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -210,7 +210,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); - + Anonymize & Archive From 45b3311f54414f6c3e972e066f65531943aca42c Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sat, 7 Oct 2023 22:44:29 +0100 Subject: [PATCH 05/20] Add function to reset all user/agent passwords in case of IR --- post/user.php | 44 +++++++++++++++++++++++++++++++ user_all_reset_password_modal.php | 31 ++++++++++++++++++++++ users.php | 5 ++++ 3 files changed, 80 insertions(+) create mode 100644 user_all_reset_password_modal.php diff --git a/post/user.php b/post/user.php index 363eb752..fcbb9e15 100644 --- a/post/user.php +++ b/post/user.php @@ -280,3 +280,47 @@ if (isset($_POST['export_users_csv'])) { exit; } + +if (isset($_POST['ir_reset_user_password'])) { + + // Incident response: allow mass reset of agent passwords + + validateAdminRole(); + + validateCSRFToken($_POST['csrf_token']); + + // Confirm logged-in user password, for security + $admin_password = $_POST['admin_password']; + $sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $session_user_id"); + $userRow = mysqli_fetch_array($sql); + if (!password_verify($admin_password, $userRow['user_password'])) { + $_SESSION['alert_type'] = "error"; + $_SESSION['alert_message'] = "Incorrect password."; + header("Location: " . $_SERVER["HTTP_REFERER"]); + exit; + } + + // Get agents/users, other than the current user + $sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE (user_archived_at IS NULL AND user_id != $session_user_id)"); + + // Reset passwords + while ($row = mysqli_fetch_array($sql_users)) { + $user_id = intval($row['user_id']); + $user_email = sanitizeInput($row['user_email']); + $new_password = randomString(); + $user_specific_encryption_ciphertext = encryptUserSpecificKey(trim($new_password)); + + echo $user_email . " -- " . $new_password; // Show + $new_password = password_hash($new_password, PASSWORD_DEFAULT); + + mysqli_query($mysqli, "UPDATE users SET user_password = '$new_password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext' WHERE user_id = $user_id"); + + echo "

"; + } + + // Logging + mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'User', log_action = 'Modify', log_description = '$session_name reset ALL user passwords', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); + + exit; // Stay on the plain text password page + +} diff --git a/user_all_reset_password_modal.php b/user_all_reset_password_modal.php new file mode 100644 index 00000000..746bfaa1 --- /dev/null +++ b/user_all_reset_password_modal.php @@ -0,0 +1,31 @@ + diff --git a/users.php b/users.php index e7435a8d..53c47673 100644 --- a/users.php +++ b/users.php @@ -33,6 +33,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); @@ -197,4 +201,5 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); require_once("user_add_modal.php"); require_once("user_invite_modal.php"); require_once("user_export_modal.php"); +require_once("user_all_reset_password_modal.php"); require_once("footer.php"); From 221a020ec7252549a3cfb0376ddcfaf9f1462cf7 Mon Sep 17 00:00:00 2001 From: Andrew Malsbury Date: Sun, 8 Oct 2023 02:06:54 +0000 Subject: [PATCH 06/20] Update Readme to suggest install script. --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/README.md b/README.md index d08dfe33..08c15859 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,44 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// 3. Create a MariaDB Database 4. Point your browser to your HTTPS web server to begin setup + +## Installation via Script (Recommended Method) + + **Security message** + This project is currently in Beta with many ongoing changes. + + Whilst we're confident the majority of code is safe, nothing in life is 100% safe or risk-free. Writing functional, secure code is very difficult. The current fast pace of development/change may unintentionally introduce bugs/security issues. Use your best judgment before storing highly confidential information in the app. You may wish to consider running ITFlow on it's own server, using a web-app firewall, restricting access (except /portal) to trusted IP addresses, etc. + Need to report a security issue? Check the [security policy](https://github.com/itflow-org/itflow/security/policy) + + ITFlow comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law + + ITFlow is self-hosted. There is a full installation guide in the [docs](https://docs.itflow.org/installation), but the TLDR is: + + + **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, NOT itflow.xyz.example.com + + **Process** + - Login as root + - Download Script + ``` + wget https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh + ``` + - Read over script to understand purpose and function + ``` + nano itflow.sh + ``` + - Close nano with `ctrl + 'X'` + - Run Scipt + ``` + bash itflow_install.sh + ``` + - Follow Instructions + - Leave us feedback in the [forum](https://forum.itflow.org/d/11-road-map) + ## Key Features * Client documentation - assets, contacts, domains, docs, files, passwords, and more From 605eda879df1112ef9f0ea2bee0ee2ae2ac22fc2 Mon Sep 17 00:00:00 2001 From: Andrew Malsbury Date: Sun, 8 Oct 2023 02:09:26 +0000 Subject: [PATCH 07/20] Updated wording --- README.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 08c15859..127a6414 100644 --- a/README.md +++ b/README.md @@ -83,20 +83,10 @@ * FullCalendar.io -## Getting Started / Installation +## Getting Started -ITFlow is self-hosted. There is a full installation guide in the [docs](https://docs.itflow.org/installation), but the main steps are: +ITFlow is self-hosted. There is a full installation guide in the [docs](https://docs.itflow.org/installation). -1. Install a LAMP stack (Linux, Apache, MariaDB, PHP) - ```sh - sudo apt install git apache2 php libapache2-mod-php php-intl php-imap php-mailparse php-mysqli php-curl mariadb-server - ``` -2. Clone the repo - ```sh - git clone https://github.com/itflow-org/itflow.git /var/www/html - ``` -3. Create a MariaDB Database -4. Point your browser to your HTTPS web server to begin setup ## Installation via Script (Recommended Method) @@ -108,9 +98,6 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// Need to report a security issue? Check the [security policy](https://github.com/itflow-org/itflow/security/policy) ITFlow comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law - - ITFlow is self-hosted. There is a full installation guide in the [docs](https://docs.itflow.org/installation), but the TLDR is: - **Requirements** - Clean Install of Debian 12 or Ubuntu 22.04 From 92eabf1e70c2dee19485d8922590217fbfa3c468 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 09:02:18 +0100 Subject: [PATCH 08/20] Update README.md / Update readme with install script #737 --- README.md | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 127a6414..fc49952e 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Report Bug · Request Feature + · + Security

@@ -89,16 +91,8 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// -## Installation via Script (Recommended Method) - - **Security message** - This project is currently in Beta with many ongoing changes. - - Whilst we're confident the majority of code is safe, nothing in life is 100% safe or risk-free. Writing functional, secure code is very difficult. The current fast pace of development/change may unintentionally introduce bugs/security issues. Use your best judgment before storing highly confidential information in the app. You may wish to consider running ITFlow on it's own server, using a web-app firewall, restricting access (except /portal) to trusted IP addresses, etc. - Need to report a security issue? Check the [security policy](https://github.com/itflow-org/itflow/security/policy) - - ITFlow comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law - +### Installation via Script (Recommended Method) + **Requirements** - Clean Install of Debian 12 or Ubuntu 22.04 - A public IP Address @@ -107,20 +101,10 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// **Process** - Login as root - - Download Script + - Download & run install script ``` - wget https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh - ``` - - Read over script to understand purpose and function - ``` - nano itflow.sh - ``` - - Close nano with `ctrl + 'X'` - - Run Scipt - ``` - bash itflow_install.sh - ``` - - Follow Instructions + wget 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) From b9cadd508d1dc0c11227bae0fc01650d310d50d5 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 09:03:25 +0100 Subject: [PATCH 09/20] Update README.md / Update readme with install script #737 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fc49952e..0bc47c49 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// - Download & run install script ``` wget 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) From 623ebc783c94682ea39b91ec5152592000215ed1 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sun, 8 Oct 2023 13:35:13 +0100 Subject: [PATCH 10/20] Contacts phone numbers - add tel: hyperlink for click-to-call --- client_contact_details.php | 58 +++++++++++++++++++------------------- client_contacts.php | 4 +-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client_contact_details.php b/client_contact_details.php index cffa00b1..ee959f97 100644 --- a/client_contact_details.php +++ b/client_contact_details.php @@ -96,10 +96,10 @@ if (isset($_GET['contact_id'])) {
-
+ -
+
@@ -549,36 +549,36 @@ if (isset($_GET['contact_id'])) { - + // Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES + jQuery.post( + "ajax.php", + { + contact_set_notes: 'TRUE', + contact_id: contact_id, + notes: notes + } + ) + } + - - + $contact_phone$contact_extension_display"; + $contact_phone_display = ""; } $contact_mobile = formatPhoneNumber($row['contact_mobile']); if (empty($contact_mobile)) { $contact_mobile_display = ""; } else { - $contact_mobile_display = "
$contact_mobile
"; + $contact_mobile_display = ""; } $contact_email = nullable_htmlentities($row['contact_email']); if (empty($contact_email)) { From 4025cfdceade32cf3555aa1d100609733f8b271e Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:28:53 +0100 Subject: [PATCH 11/20] Update support.md Refer bugs/features/support to forum --- .github/ISSUE_TEMPLATE/support.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/support.md b/.github/ISSUE_TEMPLATE/support.md index cd6ca6f3..1dddb5e3 100644 --- a/.github/ISSUE_TEMPLATE/support.md +++ b/.github/ISSUE_TEMPLATE/support.md @@ -1,17 +1,24 @@ --- name: Support -about: Please visit the Forum or Discord for support -title: '' +about: Please request support on the Forum @ https://forum.itflow.org/t/support +title: 'Please visit the Forum for support' labels: Support assignees: '' --- -Please visit the Forum or Discord for support +We're now using GitHub Issues exclusively for development. +- -Forum - https://forum.itflow.org/ +Going forward, GitHub Issues will be used to track confirmed bugs & planned features via Github Projects. This allows us to keep GitHub clean & tidy, whilst maintaining an active and relaxed community experience on the Forum. -Discord - https://discord.gg/ZjCcBzTUDr +Please use the forum for support queries/issues: https://forum.itflow.org/t/support + +All new support requests raised here will be closed. + +Thanks, + +The ITFlow team :) -- From 0f4f670f9c80a2fff51e948ee19659b2a4a36509 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:28:56 +0100 Subject: [PATCH 12/20] Update feature_request.md Refer bugs/features/support to forum --- .github/ISSUE_TEMPLATE/feature_request.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index eb5c5856..926f6522 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,16 +1,25 @@ --- name: Feature request about: Please discuss new features on the Forum @ https://forum.itflow.org/t/features -title: '' +title: 'Please discuss new features on the Forum' labels: Support assignees: '' --- -We're now using GitHub just to track features we're definitely planning to implement (and bugs!). +We're now using GitHub Issues exclusively for development. +- -Please discuss new feature requests on the forum @ https://forum.itflow.org/t/features. This allows us to gather interest & feedback on the features people feel are most important, whilst keeping GitHub cleaner and more about the code. +Going forward, GitHub Issues will be used to track confirmed bugs & planned features via Github Projects. This allows us to keep GitHub clean & tidy, whilst maintaining an active and relaxed community experience on the Forum. -New feature requests here will be closed. +Please discuss new feature requests on the forum @ https://forum.itflow.org/t/features. When creating discussions, try to imagine how your proposed feature would also benefit other users. -Thanks :) +All new feature requests raised here will be closed, unless agreed otherwise. + +Thanks, + +The ITFlow team :) + +-- + +To privately discuss a security issue, please see https://github.com/itflow-org/itflow/security From 57403e17073deab0c49118307d5362f978bb8bcc Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:29:01 +0100 Subject: [PATCH 13/20] Update bug_report.md Refer bugs/features/support to forum --- .github/ISSUE_TEMPLATE/bug_report.md | 31 ++++++++-------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d95efcb2..c12ca08b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,35 +1,22 @@ --- name: Bug report -about: Something not working quite right? Create a report to help us improve! -title: '' -labels: '' +about: Please report bugs on the Forum @ https://forum.itflow.org/t/bug +title: 'Please report bugs on the Forum' +labels: Support assignees: '' --- -**Describe the bug** -A clear and concise description of what the bug is. +We're now using GitHub Issues exclusively for development. +- -**Can you reproduce this on the demo at demo.itflow.org** -Yes/No/NA +Going forward, GitHub Issues will be used to track confirmed bugs & planned features via Github Projects. This allows us to keep GitHub clean & tidy, whilst maintaining an active and relaxed community experience on the Forum. -**Are you on the latest available version of ITFlow, with an up-to-date database structure?** -Yes/No +Please raise bugs on the forum @ https://forum.itflow.org/t/bug. Make sure to mention whether you can replicate the bug on demo.itflow.org. -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -4. See error +Thanks, -**Expected behavior** -A clear and concise description of what you expected to happen, if not obvious. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. +The ITFlow team :) -- From cd006d0625d638880fe3d6e1c4210eb14e504dbd Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:32:21 +0100 Subject: [PATCH 14/20] Update first-interaction.yml Refer bugs/features/support to forum --- .github/workflows/first-interaction.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/first-interaction.yml b/.github/workflows/first-interaction.yml index 1ccf5f8a..8c6dbc7f 100644 --- a/.github/workflows/first-interaction.yml +++ b/.github/workflows/first-interaction.yml @@ -16,9 +16,9 @@ jobs: issue-message: | Hello & Welcome! :) - Thanks for taking the time to get in touch. We'll review this issue shortly. + Thanks for taking the time to get in touch. - Whilst you're waiting, please feel free to check out the [forum](https://forum.itflow.org). + We ask that all bugs/feature/support requests are raised via the [forum](https://forum.itflow.org). We'll be in touch shortly to confirm. pr-message: | Hello & Welcome! :) From f241d247be82f032a46b23bac0f8f4b59f9ec88c Mon Sep 17 00:00:00 2001 From: Andrew Malsbury Date: Sun, 8 Oct 2023 13:07:56 -0500 Subject: [PATCH 15/20] Update oneliner to not save the install file. Updated oneliner to pipe the script directly to bash. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bc47c49..a9cc5dab 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ ITFlow is self-hosted. There is a full installation guide in the [docs](https:// - Login as root - Download & run install script ``` - wget https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh && bash itflow_install.sh + wget -O - https://github.com/itflow-org/itflow-install-script/raw/main/itflow_install.sh | bash ``` - Follow Instructions & navigate to setup URL shown - Leave us feedback in the [forum](https://forum.itflow.org/d/11-road-map) From ac51e6a8ad6c092748c9ecffca07fb7f5468bb12 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 20:09:17 +0100 Subject: [PATCH 16/20] Update SECURITY.md Reword security policy, include an escalation process (forum private discussion) --- SECURITY.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index e18a4433..0edc6ff6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,9 @@ # Security Policy +## **Please do NOT report security concerns/vulnerabilities publicly (Github issues/forum)** + +--- + ## In Beta ITFlow is currently in beta and is a work in progress. @@ -14,10 +18,10 @@ We attempt to follow security best practices where possible, including [automate | ------- | ------------------ | | Beta | :white_check_mark: | -## Reporting a Vulnerability - -**Please do not report security vulnerabilities through public GitHub issues.** - -If you have discovered a security issue, please [report it](https://github.com/itflow-org/itflow/security/advisories/new) to us in as much detail as possible, so we can fix it. You should expect to receive an initial acknowledgement within 72 hours. +## Reporting a Vulnerability via GitHub Security Advisories **Security contact: [GitHub Security Advisories](https://github.com/itflow-org/itflow/security/advisories/new)** + +If you have discovered a security issue, please **[report it](https://github.com/itflow-org/itflow/security/advisories/new)** to us in as much detail as possible, so we can fix it. + +You should expect to receive an initial acknowledgement within 72 hours. If you don't receive any feedback, we may have missed the initial email from GitHub (we're human!). Please raise a private forum discussion with johnny and wrongecho quoting ONLY the assigned GHSA ref. From 5b49d35f1a0241060c0f83ee696aa53df2f3c782 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Sun, 8 Oct 2023 20:13:42 +0100 Subject: [PATCH 17/20] Update SECURITY.md Add placeholder for 1.0 --- SECURITY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SECURITY.md b/SECURITY.md index 0edc6ff6..b5f161ca 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -17,6 +17,7 @@ We attempt to follow security best practices where possible, including [automate | Version | Supported | | ------- | ------------------ | | Beta | :white_check_mark: | +| 1.0 | Yet to be released | ## Reporting a Vulnerability via GitHub Security Advisories From 22f14cd5e72739360baa1376c18cf44474dfb002 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sun, 8 Oct 2023 21:30:15 +0100 Subject: [PATCH 18/20] Telemetry - Fix typo & add polite note regarding importance of telemetry data --- settings_telemetry.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/settings_telemetry.php b/settings_telemetry.php index 8a7c29bc..53fcbd30 100644 --- a/settings_telemetry.php +++ b/settings_telemetry.php @@ -12,7 +12,8 @@ require_once("inc_all_settings.php"); ?>
- + +

If you can't measure it, you can't improve it. Please consider turning on telemetry data to provide valuable insights on how you're using ITFlow - so we can improve it for everyone.

@@ -23,12 +24,12 @@ require_once("inc_all_settings.php"); ?>
- Click Here for additional details regarding the information we gather + We respect your privacy. Click here for additional details regarding the information we gather.
- +

From 43dc95c55a190197ff222ee50e6d13c9e8729b03 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 8 Oct 2023 19:59:26 -0400 Subject: [PATCH 19/20] Fix missing
in ticket when we tried to fix merge conflicts --- ticket.php | 1 + 1 file changed, 1 insertion(+) diff --git a/ticket.php b/ticket.php index 738347bb..8e66646e 100644 --- a/ticket.php +++ b/ticket.php @@ -336,6 +336,7 @@ if (isset($_GET['ticket_id'])) { + From 537f18efd263a2ad5bf2518100288e8f336ff57e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 8 Oct 2023 20:03:16 -0400 Subject: [PATCH 20/20] Fix Incorrect var when setting timezone --- check_login.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/check_login.php b/check_login.php index 1d071ea7..4549c857 100644 --- a/check_login.php +++ b/check_login.php @@ -45,17 +45,17 @@ if ($session_user_role == 3) { $session_user_config_force_mfa = intval($row['user_config_force_mfa']); $user_config_records_per_page = intval($row['user_config_records_per_page']); -$sql = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); +$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE settings.company_id = companies.company_id AND companies.company_id = 1"); $row = mysqli_fetch_array($sql); $session_company_name = $row['company_name']; $session_company_country = $row['company_country']; $session_company_locale = $row['company_locale']; $session_company_currency = $row['company_currency']; -$session_company_timezone = $row['company_timezone']; +$session_timezone = $row['settings_timezone']; // Set Timezone to the companies timezone -date_default_timezone_set('$session_company_timezone'); +date_default_timezone_set('$session_timezone'); //Set Currency Format $currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY);