Merge branch 'itflow-org:master' into balance-sheet

This commit is contained in:
Andrew Malsbury
2023-10-10 08:27:14 -05:00
committed by GitHub
21 changed files with 279 additions and 172 deletions

View File

@@ -1,35 +1,22 @@
--- ---
name: Bug report name: Bug report
about: Something not working quite right? Create a report to help us improve! about: Please report bugs on the Forum @ https://forum.itflow.org/t/bug
title: '' title: 'Please report bugs on the Forum'
labels: '' labels: Support
assignees: '' assignees: ''
--- ---
**Describe the bug** We're now using GitHub Issues exclusively for development.
A clear and concise description of what the bug is. -
**Can you reproduce this on the demo at demo.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.
Yes/No/NA
**Are you on the latest available version of ITFlow, with an up-to-date database structure?** 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.
Yes/No
**To Reproduce** Thanks,
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
4. See error
**Expected behavior** The ITFlow team :)
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.
-- --

View File

@@ -1,16 +1,25 @@
--- ---
name: Feature request name: Feature request
about: Please discuss new features on the Forum @ https://forum.itflow.org/t/features 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 labels: Support
assignees: '' 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

View File

@@ -1,17 +1,24 @@
--- ---
name: Support name: Support
about: Please visit the Forum or Discord for support about: Please request support on the Forum @ https://forum.itflow.org/t/support
title: '' title: 'Please visit the Forum for support'
labels: Support labels: Support
assignees: '' 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 :)
-- --

View File

@@ -16,9 +16,9 @@ jobs:
issue-message: | issue-message: |
Hello & Welcome! :) 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: | pr-message: |
Hello & Welcome! :) Hello & Welcome! :)

View File

@@ -33,6 +33,8 @@
<a href="https://github.com/itflow-org/itflow/issues">Report Bug</a> <a href="https://github.com/itflow-org/itflow/issues">Report Bug</a>
· ·
<a href="https://forum.itflow.org/t/features">Request Feature</a> <a href="https://forum.itflow.org/t/features">Request Feature</a>
·
<a href="https://github.com/itflow-org/itflow/security/policy">Security</a>
</p> </p>
</div> </div>
@@ -83,20 +85,28 @@
* FullCalendar.io * FullCalendar.io
<!-- GETTING STARTED --> <!-- GETTING STARTED -->
## 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 <!-- EASY INSTALL -->
sudo apt install git apache2 php libapache2-mod-php php-intl php-imap php-mailparse php-mysqli php-curl mariadb-server ### Installation via Script (Recommended Method)
```
2. Clone the repo **Requirements**
```sh - Clean Install of Debian 12 or Ubuntu 22.04
git clone https://github.com/itflow-org/itflow.git /var/www/html - A public IP Address
``` - Ports 80 (HTTP) and 443 (HTTPS) TCP accessible from the outside in
3. Create a MariaDB Database - A Fully Qualified Domain Name pointing to the public IP Address example itflow.example.com, NOT itflow.xyz.example.com
4. Point your browser to your HTTPS web server to begin setup
**Process**
- Login as root
- Download & run install script
```
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)
<!-- FEATURES --> <!-- FEATURES -->
## Key Features ## Key Features

View File

@@ -1,5 +1,9 @@
# Security Policy # Security Policy
## **Please do NOT report security concerns/vulnerabilities publicly (Github issues/forum)**
---
## In Beta ## In Beta
ITFlow is currently in beta and is a work in progress. ITFlow is currently in beta and is a work in progress.
@@ -13,11 +17,12 @@ We attempt to follow security best practices where possible, including [automate
| Version | Supported | | Version | Supported |
| ------- | ------------------ | | ------- | ------------------ |
| Beta | :white_check_mark: | | Beta | :white_check_mark: |
| 1.0 | Yet to be released |
## Reporting a Vulnerability ## Reporting a Vulnerability via GitHub Security Advisories
**<ins>Please do not report security vulnerabilities through public GitHub issues.</ins>**
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.
**Security contact: [GitHub Security Advisories](https://github.com/itflow-org/itflow/security/advisories/new)** **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.

View File

@@ -45,17 +45,17 @@ if ($session_user_role == 3) {
$session_user_config_force_mfa = intval($row['user_config_force_mfa']); $session_user_config_force_mfa = intval($row['user_config_force_mfa']);
$user_config_records_per_page = intval($row['user_config_records_per_page']); $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); $row = mysqli_fetch_array($sql);
$session_company_name = $row['company_name']; $session_company_name = $row['company_name'];
$session_company_country = $row['company_country']; $session_company_country = $row['company_country'];
$session_company_locale = $row['company_locale']; $session_company_locale = $row['company_locale'];
$session_company_currency = $row['company_currency']; $session_company_currency = $row['company_currency'];
$session_company_timezone = $row['company_timezone']; $session_timezone = $row['settings_timezone'];
// Set Timezone to the companies timezone // Set Timezone to the companies timezone
date_default_timezone_set('$session_company_timezone'); date_default_timezone_set('$session_timezone');
//Set Currency Format //Set Currency Format
$currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY); $currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY);

View File

@@ -96,10 +96,10 @@ if (isset($_GET['contact_id'])) {
<div><i class="fa fa-fw fa-envelope text-secondary mr-3"></i><a href='mailto:<?php echo $contact_email; ?>'><?php echo $contact_email; ?></a><button class='btn btn-sm clipboardjs' data-clipboard-text='<?php echo $contact_email; ?>'><i class='far fa-copy text-secondary'></i></button></div> <div><i class="fa fa-fw fa-envelope text-secondary mr-3"></i><a href='mailto:<?php echo $contact_email; ?>'><?php echo $contact_email; ?></a><button class='btn btn-sm clipboardjs' data-clipboard-text='<?php echo $contact_email; ?>'><i class='far fa-copy text-secondary'></i></button></div>
<?php } <?php }
if (!empty($contact_phone)) { ?> if (!empty($contact_phone)) { ?>
<div class="mb-2"><i class="fa fa-fw fa-phone text-secondary mr-3"></i><?php echo "$contact_phone $contact_extension"; ?></div> <div class="mb-2"><i class="fa fa-fw fa-phone text-secondary mr-3"></i><a href="tel:<?php echo "$contact_phone"?>"><?php echo "$contact_phone $contact_extension"; ?></a></div>
<?php } <?php }
if (!empty($contact_mobile)) { ?> if (!empty($contact_mobile)) { ?>
<div class="mb-2"><i class="fa fa-fw fa-mobile-alt text-secondary mr-3"></i><?php echo $contact_mobile; ?></div> <div class="mb-2"><i class="fa fa-fw fa-mobile-alt text-secondary mr-3"></i><a href="tel:<?php echo $contact_mobile; ?>"><?php echo $contact_mobile; ?></a></div>
<?php } <?php }
if (!empty($contact_pin)) { ?> if (!empty($contact_pin)) { ?>
<div class="mb-2"><i class="fa fa-fw fa-key text-secondary mr-3"></i><?php echo $contact_pin; ?></div> <div class="mb-2"><i class="fa fa-fw fa-key text-secondary mr-3"></i><?php echo $contact_pin; ?></div>
@@ -549,36 +549,36 @@ if (isset($_GET['contact_id'])) {
<?php } ?> <?php } ?>
<script> <script>
function updateContactNotes(contact_id) { function updateContactNotes(contact_id) {
var notes = document.getElementById("contactNotes").value; var notes = document.getElementById("contactNotes").value;
// Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES // Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES
jQuery.post( jQuery.post(
"ajax.php", "ajax.php",
{ {
contact_set_notes: 'TRUE', contact_set_notes: 'TRUE',
contact_id: contact_id, contact_id: contact_id,
notes: notes notes: notes
} }
) )
} }
</script> </script>
<!-- JavaScript to Show/Hide Password Form Group --> <!-- JavaScript to Show/Hide Password Form Group -->
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('.authMethod').on('change', function() { $('.authMethod').on('change', function() {
var $form = $(this).closest('.authForm'); var $form = $(this).closest('.authForm');
if ($(this).val() === 'local') { if ($(this).val() === 'local') {
$form.find('.passwordGroup').show(); $form.find('.passwordGroup').show();
} else { } else {
$form.find('.passwordGroup').hide(); $form.find('.passwordGroup').hide();
} }
});
$('.authMethod').trigger('change');
}); });
$('.authMethod').trigger('change'); </script>
});
</script>
<?php <?php
require_once("footer.php"); require_once("footer.php");

View File

@@ -13,6 +13,7 @@
<input type="hidden" name="contact_important" value="0"> <input type="hidden" name="contact_important" value="0">
<input type="hidden" name="contact_billing" value="0"> <input type="hidden" name="contact_billing" value="0">
<input type="hidden" name="contact_technical" value="0"> <input type="hidden" name="contact_technical" value="0">
<input type="hidden" name="send_email" value="0">
<!-- End prevent undefined errors --> <!-- End prevent undefined errors -->
<input type="hidden" name="contact_id" value="<?php echo $contact_id; ?>"> <input type="hidden" name="contact_id" value="<?php echo $contact_id; ?>">
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>"> <input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
@@ -198,7 +199,7 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div> </div>
<input type="password" class="form-control" data-toggle="password" name="contact_password" placeholder="Leave blank for no change" autocomplete="new-password"> <input type="password" class="form-control" data-toggle="password" name="contact_password" placeholder="Leave blank for no change" autocomplete="new-password" minlength="8">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div> </div>
@@ -207,7 +208,7 @@
</div> </div>
<div class="form-check"> <div class="form-check">
<input type="checkbox" class="form-check-input" name="send_email" value=""/> <input type="checkbox" class="form-check-input" name="send_email" value="1"/>
<label class="form-check-label">Send user e-mail with login details?</label> <label class="form-check-label">Send user e-mail with login details?</label>
</div> </div>
@@ -252,4 +253,4 @@
</form> </form>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -111,14 +111,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
if (empty($contact_phone)) { if (empty($contact_phone)) {
$contact_phone_display = ""; $contact_phone_display = "";
} else { } else {
$contact_phone_display = "<div><i class='fas fa-fw fa-phone mr-2'></i>$contact_phone$contact_extension_display</div>"; $contact_phone_display = "<div><i class='fas fa-fw fa-phone mr-2'></i><a href='tel:$contact_phone'>$contact_phone$contact_extension_display</a></div>";
} }
$contact_mobile = formatPhoneNumber($row['contact_mobile']); $contact_mobile = formatPhoneNumber($row['contact_mobile']);
if (empty($contact_mobile)) { if (empty($contact_mobile)) {
$contact_mobile_display = ""; $contact_mobile_display = "";
} else { } else {
$contact_mobile_display = "<div class='mt-2'><i class='fas fa-fw fa-mobile-alt mr-2'></i>$contact_mobile</div>"; $contact_mobile_display = "<div class='mt-2'><i class='fas fa-fw fa-mobile-alt mr-2'></i><a href='tel:$contact_mobile'>$contact_mobile</a></div>";
} }
$contact_email = nullable_htmlentities($row['contact_email']); $contact_email = nullable_htmlentities($row['contact_email']);
if (empty($contact_email)) { if (empty($contact_email)) {
@@ -210,7 +210,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</a> </a>
<?php if ($session_user_role == 3 && $contact_primary == 0) { ?> <?php if ($session_user_role == 3 && $contact_primary == 0) { ?>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="post.php?anonymize_contact=<?php echo $contact_id; ?>"> <a class="dropdown-item text-danger confirm-link" href="post.php?anonymize_contact=<?php echo $contact_id; ?>">
<i class="fas fa-fw fa-user-secret mr-2"></i>Anonymize & Archive <i class="fas fa-fw fa-user-secret mr-2"></i>Anonymize & Archive
</a> </a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>

View File

@@ -72,6 +72,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$domain_webhost = intval($row['domain_webhost']); $domain_webhost = intval($row['domain_webhost']);
$domain_expire = nullable_htmlentities($row['domain_expire']); $domain_expire = nullable_htmlentities($row['domain_expire']);
$domain_registrar_name = nullable_htmlentities($row['vendor_name']); $domain_registrar_name = nullable_htmlentities($row['vendor_name']);
$domain_created_at = nullable_htmlentities($row['domain_created_at']);
if (empty($domain_registrar_name)) { if (empty($domain_registrar_name)) {
$domain_registrar_name = "-"; $domain_registrar_name = "-";
} }
@@ -82,7 +83,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
if ($row) { if ($row) {
$domain_webhost_name = nullable_htmlentities($row['vendor_name']); $domain_webhost_name = nullable_htmlentities($row['vendor_name']);
} }
$domain_created_at = nullable_htmlentities($row['domain_created_at']);
?> ?>
<tr> <tr>

View File

@@ -94,9 +94,9 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
// Prep ticket details // Prep ticket details
$message = nl2br($message); $message = nl2br($message);
$message = mysqli_real_escape_string($mysqli, "<i>Email from: $contact_email at $date:-</i> <br><br>$message"); $message_escaped = mysqli_real_escape_string($mysqli, "<i>Email from: $contact_email at $date:-</i> <br><br>$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); $id = mysqli_insert_id($mysqli);
// Logging // 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 // E-mail client notification that ticket has been created
if ($config_ticket_client_general_notifications == 1) { if ($config_ticket_client_general_notifications == 1) {
$email_subject = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"; // Insert email into queue (first, escape vars)
$email_body = "<i style='color: #808080'>##- Please type your reply above this line -##</i><br><br>Hello, $contact_name<br><br>Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.<br><br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $subject<br>Status: Open<br>https://$config_base_url/portal/ticket.php?id=$id<br><br>~<br>$company_name<br>Support Department<br>$config_ticket_from_email<br>$company_phone"; $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( $subject_escaped = mysqli_escape_string($mysqli, "Ticket created - [$config_ticket_prefix$ticket_number] - $subject");
$config_smtp_host, $body_escaped = mysqli_escape_string($mysqli, "<i style='color: #808080'>##- Please type your reply above this line -##</i><br><br>Hello, $contact_name<br><br>Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.<br><br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $subject<br>Status: Open<br>https://$config_base_url/portal/ticket.php?id=$id<br><br>~<br>$company_name<br>Support Department<br>$config_ticket_from_email<br>$company_phone");
$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
);
if ($mail !== true) { 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'");
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'");
}
} }
@@ -173,8 +162,10 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
$client_row = mysqli_fetch_array($client_sql); $client_row = mysqli_fetch_array($client_sql);
$client_name = sanitizeInput($client_row['client_name']); $client_name = sanitizeInput($client_row['client_name']);
$details = removeEmoji($message); // TODO: Fix Emojis and HTML opening tags sometimes breaking this "forwarding"
$email_subject = "ITFlow - New Ticket - $client_name: $subject"; $details = removeEmoji($message_escaped);
$email_subject = mysqli_escape_string($mysqli, "ITFlow - New Ticket - $client_name: $subject");
$email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: Low (email parsed)<br>Link: https://$config_base_url/ticket.php?ticket_id=$id <br><br>--------------------------------<br><br><b>$subject</b><br>$details"; $email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: Low (email parsed)<br>Link: https://$config_base_url/ticket.php?ticket_id=$id <br><br>--------------------------------<br><br><b>$subject</b><br>$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'"); 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'))))); $date = trim(mysqli_real_escape_string($mysqli, nullable_htmlentities(strip_tags($parser->getHeader('date')))));
$attachments = $parser->getAttachments(); $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'); $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) // Check if we can identify a ticket number (in square brackets)
if (preg_match("/\[$config_ticket_prefix\d+\]/", $subject, $ticket_number)) { 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 // 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 // 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 // We found a match - create a contact under this client and raise a ticket for them
// Client details // Client details
$client_id = intval($row['client_id']); $client_id = intval($row['domain_client_id']);
// Contact details // Contact details
$password = password_hash(randomString(), PASSWORD_DEFAULT); $password = password_hash(randomString(), PASSWORD_DEFAULT);

View File

@@ -516,7 +516,7 @@ function sendSingleEmail($config_smtp_host, $config_smtp_username, $config_smtp_
$smtp_auth = true; $smtp_auth = true;
} }
try{ try {
// Mail Server Settings // Mail Server Settings
$mail->CharSet = "UTF-8"; // Specify UTF-8 charset to ensure symbols ($/£) load correctly $mail->CharSet = "UTF-8"; // Specify UTF-8 charset to ensure symbols ($/£) load correctly
$mail->SMTPDebug = 0; // No Debugging $mail->SMTPDebug = 0; // No Debugging
@@ -712,13 +712,13 @@ function shortenClient($client) {
// Break into words. // Break into words.
$words = explode(' ', trim($cleaned)); $words = explode(' ', trim($cleaned));
$shortened = ''; $shortened = '';
// If there's only one word. // If there's only one word.
if (count($words) == 1) { if (count($words) == 1) {
$word = $words[0]; $word = $words[0];
if (strlen($word) <= 3) { if (strlen($word) <= 3) {
return strtoupper($word); return strtoupper($word);
} }
@@ -753,22 +753,22 @@ function roundToNearest15($time) {
// Extract hours, minutes, and seconds from the matched time string // Extract hours, minutes, and seconds from the matched time string
list(, $hours, $minutes, $seconds) = $matches; list(, $hours, $minutes, $seconds) = $matches;
// Convert everything to seconds for easier calculation // Convert everything to seconds for easier calculation
$totalSeconds = ($hours * 3600) + ($minutes * 60) + $seconds; $totalSeconds = ($hours * 3600) + ($minutes * 60) + $seconds;
// Calculate the remainder when divided by 900 seconds (15 minutes) // Calculate the remainder when divided by 900 seconds (15 minutes)
$remainder = $totalSeconds % 900; $remainder = $totalSeconds % 900;
if ($remainder > 450) { // If remainder is more than 7.5 minutes (450 seconds), round up if ($remainder > 450) { // If remainder is more than 7.5 minutes (450 seconds), round up
$totalSeconds += (900 - $remainder); $totalSeconds += (900 - $remainder);
} else { // Else round down } else { // Else round down
$totalSeconds -= $remainder; $totalSeconds -= $remainder;
} }
// Convert total seconds to decimal hours // Convert total seconds to decimal hours
$decimalHours = $totalSeconds / 3600; $decimalHours = $totalSeconds / 3600;
// Return the decimal hours // Return the decimal hours
return number_format($decimalHours, 2); return number_format($decimalHours, 2);
} }

View File

@@ -50,6 +50,7 @@ $session_contact_initials = initials($session_contact_name);
$session_contact_title = sanitizeInput($contact['contact_title']); $session_contact_title = sanitizeInput($contact['contact_title']);
$session_contact_email = sanitizeInput($contact['contact_email']); $session_contact_email = sanitizeInput($contact['contact_email']);
$session_contact_photo = sanitizeInput($contact['contact_photo']); $session_contact_photo = sanitizeInput($contact['contact_photo']);
$session_contact_pin = sanitizeInput($contact['contact_pin']);
$session_contact_primary = intval($contact['contact_primary']); $session_contact_primary = intval($contact['contact_primary']);
$session_contact_is_technical_contact = false; $session_contact_is_technical_contact = false;

View File

@@ -13,6 +13,7 @@ require_once('inc_portal.php');
<p>Name: <?php echo $session_contact_name ?></p> <p>Name: <?php echo $session_contact_name ?></p>
<p>Email: <?php echo $session_contact_email ?></p> <p>Email: <?php echo $session_contact_email ?></p>
<p>PIN: <?php echo $session_contact_pin ?></p>
<p>Client: <?php echo $session_client_name ?></p> <p>Client: <?php echo $session_client_name ?></p>
<br> <br>
<p>Client Primary Contact: <?php if ($session_contact_primary == 1) {echo "Yes"; } else {echo "No";} ?></p> <p>Client Primary Contact: <?php if ($session_contact_primary == 1) {echo "Yes"; } else {echo "No";} ?></p>
@@ -35,7 +36,7 @@ require_once('inc_portal.php');
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div> </div>
<input type="password" class="form-control" minlength="6" required data-toggle="password" name="new_password" placeholder="Leave blank for no change" autocomplete="new-password"> <input type="password" class="form-control" minlength="8" required data-toggle="password" name="new_password" placeholder="Leave blank for no change" autocomplete="new-password">
</div> </div>
</div> </div>
<button type="submit" name="edit_profile" class="btn btn-primary text-bold mt-3"><i class="fas fa-check mr-2"></i>Save password</button> <button type="submit" name="edit_profile" class="btn btn-primary text-bold mt-3"><i class="fas fa-check mr-2"></i>Save password</button>

View File

@@ -17,7 +17,7 @@ if (isset($_POST['add_contact'])) {
// Set a random password // Set a random password
$password_hash = password_hash(randomString(), PASSWORD_DEFAULT); $password_hash = password_hash(randomString(), PASSWORD_DEFAULT);
} }
if (!file_exists("uploads/clients/$client_id")) { if (!file_exists("uploads/clients/$client_id")) {
mkdir("uploads/clients/$client_id"); mkdir("uploads/clients/$client_id");
} }
@@ -68,6 +68,7 @@ if (isset($_POST['edit_contact'])) {
require_once('post/contact_model.php'); require_once('post/contact_model.php');
$contact_id = intval($_POST['contact_id']); $contact_id = intval($_POST['contact_id']);
$send_email = intval($_POST['send_email']);
// Get Exisiting Contact Photo // Get Exisiting Contact Photo
$sql = mysqli_query($mysqli,"SELECT contact_photo FROM contacts WHERE contact_id = $contact_id"); $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 // 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 // Un-sanitizied used in body of email
$contact_name = $_POST['name']; $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_email_escaped = sanitizeInput($config_ticket_from_email);
$config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name);
// Authentication info (azure, reset password, or tech-provided temporary password)
if ($auth_method == 'azure') { if ($auth_method == 'azure') {
$password_info = "Login with your Microsoft (Azure AD) account."; $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 { } 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"); $subject = sanitizeInput("Your new $session_company_name support portal account");
$body = mysqli_real_escape_string($mysqli, "Hello, $contact_name<br><br>An ITFlow account has been set up for you. <br><br>Username: $email <br>Password: $password_info<br><br>Login URL: https://$config_base_url/portal/<br><br>~<br>$session_company_name<br>Support Department<br>$config_ticket_from_email"); $body = mysqli_real_escape_string($mysqli, "Hello, $contact_name<br><br>$session_company_name has created a support portal account for you. <br><br>Username: $email<br>Password: $password_info<br><br>Login URL: https://$config_base_url/portal/<br><br>~<br>$session_company_name<br>Support Department<br>$config_ticket_from_email");
// Queue Mail // 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'"); 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'");

View File

@@ -280,3 +280,47 @@ if (isset($_POST['export_users_csv'])) {
exit; 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 "<br><br>";
}
// 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
}

View File

@@ -12,7 +12,8 @@ require_once("inc_all_settings.php"); ?>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<div class="form-group"> <div class="form-group">
<label>Telemery</label> <label>Telemetry</label>
<p><i>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. </i></p>
<div class="input-group"> <div class="input-group">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-broadcast-tower"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-broadcast-tower"></i></span>
@@ -23,12 +24,12 @@ require_once("inc_all_settings.php"); ?>
<option <?php if ($config_telemetry == "2") { echo "selected"; } ?> value = "2">Detailed</option> <option <?php if ($config_telemetry == "2") { echo "selected"; } ?> value = "2">Detailed</option>
</select> </select>
</div> </div>
<small class="form-text"><a href="https://docs.itflow.org/telemetry" target="_blank">Click Here for additional details regarding the information we gather <i class="fas fa-external-link-alt"></i></a></small> <small class="form-text">We respect your privacy. <a href="https://docs.itflow.org/telemetry" target="_blank">Click here <i class="fas fa-external-link-alt"></i></a> for additional details regarding the information we gather. </small>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Comments</label> <label>Comments</label>
<textarea class="form-control" rows="4" name="comments" placeholder="Any Comments to send before hitting Send Telemetry Data?"></textarea> <textarea class="form-control" rows="4" name="comments" placeholder="Any one-off comments to send before hitting Send Telemetry Data?"></textarea>
</div> </div>
<hr> <hr>

View File

@@ -326,8 +326,9 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
</div> </div>
<?php if(!empty($contact_email)){ ?>
<?php if(!empty($contact_email && $contact_email !== $session_email)){ ?>
<div class="col-md-2"> <div class="col-md-2">
<div class="form-group"> <div class="form-group">
<div class="custom-control custom-checkbox"> <div class="custom-control custom-checkbox">
@@ -483,13 +484,13 @@ if (isset($_GET['ticket_id'])) {
<!-- Contact card --> <!-- Contact card -->
<div class="card card-body card-outline card-dark mb-3"> <div class="card card-body card-outline card-dark mb-3">
<h4 class="text-secondary">Contact</h4> <h4 class="text-secondary">Contact</h4>
<?php if (!empty($contact_id)) { ?> <?php if (!empty($contact_id)) { ?>
<div> <div>
<i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i><a href="#" data-toggle="modal" data-target="#editTicketContactModal<?php echo $ticket_id; ?>"><strong><?php echo $contact_name; ?></strong> <i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i><a href="#" data-toggle="modal" data-target="#editTicketContactModal<?php echo $ticket_id; ?>"><strong><?php echo $contact_name; ?></strong>
</a> </a>
</div> </div>
<?php <?php
@@ -517,32 +518,31 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
<?php } ?> <?php } ?>
<hr>
<?php <?php
// Previous tickets
$prev_ticket_id = $prev_ticket_subject = $prev_ticket_status = ''; // Default blank
$sql_prev_ticket = "SELECT ticket_id, ticket_created_at, ticket_subject, ticket_status, ticket_assigned_to FROM tickets WHERE ticket_contact_id = $contact_id AND ticket_id <> $ticket_id ORDER BY ticket_id DESC LIMIT 1"; $sql_prev_ticket = "SELECT ticket_id, ticket_created_at, ticket_subject, ticket_status, ticket_assigned_to FROM tickets WHERE ticket_contact_id = $contact_id AND ticket_id <> $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']); if ($prev_ticket_row) {
$prev_ticket_subject = nullable_htmlentities($row['ticket_subject']); $prev_ticket_id = intval($prev_ticket_row['ticket_id']);
$prev_ticket_status = nullable_htmlentities($row['ticket_status']); $prev_ticket_subject = nullable_htmlentities($prev_ticket_row['ticket_subject']);
?> $prev_ticket_status = nullable_htmlentities($prev_ticket_row['ticket_status']);
?>
<div> <hr>
<i class="fa fa-fw fa-history text-secondary ml-1 mr-2"></i><b>Previous ticket:</b> <div>
<a href="ticket.php?ticket_id=<?php echo $prev_ticket_id; ?>"><?php echo $prev_ticket_subject; ?></a> <i class="fa fa-fw fa-history text-secondary ml-1 mr-2"></i><b>Previous ticket:</b>
</div> <a href="ticket.php?ticket_id=<?php echo $prev_ticket_id; ?>"><?php echo $prev_ticket_subject; ?></a>
<div class="mt-1"> </div>
<?php if ($prev_ticket_status == 'Open') { ?> <div class="mt-1">
<i class="fa fa-fw fa-hourglass-start text-secondary ml-1 mr-2"></i><strong>Status:</strong>
<span class="text-danger"><?php echo $prev_ticket_status; ?></span>
<?php } else { ?>
<i class="fa fa-fw fa-hourglass-start text-secondary ml-1 mr-2"></i><strong>Status:</strong> <i class="fa fa-fw fa-hourglass-start text-secondary ml-1 mr-2"></i><strong>Status:</strong>
<span class="text-success"><?php echo $prev_ticket_status; ?></span> <span class="text-success"><?php echo $prev_ticket_status; ?></span>
<?php } ?> <?php } ?>
</div> </div>
<?php } else { ?> <?php } else { ?>
<div> <div>
<a href="#" data-toggle="modal" data-target="#editTicketContactModal<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-plus mr-2"></i>Add a Contact</a> <a href="#" data-toggle="modal" data-target="#editTicketContactModal<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-plus mr-2"></i>Add a Contact</a>
@@ -565,12 +565,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"); $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)) { while ($ticket_watcher_row = mysqli_fetch_array($sql_ticket_watchers)) {
$ticket_watcher_email = nullable_htmlentities($ticket_watcher_row['watcher_email']); $ticket_watcher_email = nullable_htmlentities($ticket_watcher_row['watcher_email']);
?> ?>
<div class='mt-1'> <div class='mt-1'>
<i class="fa fa-fw fa-eye text-secondary ml-1 mr-2"></i><?php echo $ticket_watcher_email; ?> <i class="fa fa-fw fa-eye text-secondary ml-1 mr-2"></i><?php echo $ticket_watcher_email; ?>
</div> </div>
<?php } ?> <?php } ?>
</div> </div>
<!-- End Ticket watchers card --> <!-- End Ticket watchers card -->
@@ -586,14 +586,15 @@ if (isset($_GET['ticket_id'])) {
<div class="mt-2"> <div class="mt-2">
<i class="fa fa-fw fa-history text-secondary ml-1 mr-2"></i>Updated: <strong><?php echo $ticket_updated_at; ?></strong> <i class="fa fa-fw fa-history text-secondary ml-1 mr-2"></i>Updated: <strong><?php echo $ticket_updated_at; ?></strong>
</div> </div>
<?php <?php
if ($ticket_status == "Closed") { if ($ticket_status == "Closed") {
$sql_closed_by = mysqli_query($mysqli, "SELECT * FROM tickets, users WHERE ticket_closed_by = user_id"); $sql_closed_by = mysqli_query($mysqli, "SELECT * FROM tickets, users WHERE ticket_closed_by = user_id");
$row = mysqli_fetch_array($sql_closed_by); $row = mysqli_fetch_array($sql_closed_by);
$ticket_closed_by_display = nullable_htmlentities($row['user_name']); $ticket_closed_by_display = nullable_htmlentities($row['user_name']);
?> ?>
<div class="mt-1"> <div class="mt-1">
<i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i>Closed by: <?php echo ucwords($ticket_closed_by_display); ?> <i class="fa fa-fw fa-user text-secondary ml-1 mr-2"></i>Closed by: <?php echo ucwords($ticket_closed_by_display); ?>
</div> </div>
@@ -601,7 +602,7 @@ if (isset($_GET['ticket_id'])) {
<i class="fa fa-fw fa-comment-dots text-secondary ml-1 mr-2"></i>Feedback: <?php echo $ticket_feedback; ?> <i class="fa fa-fw fa-comment-dots text-secondary ml-1 mr-2"></i>Feedback: <?php echo $ticket_feedback; ?>
</div> </div>
<?php } ?> <?php } ?>
<?php if (!empty($ticket_total_reply_time)) { ?> <?php if (!empty($ticket_total_reply_time)) { ?>
<div class="mt-1"> <div class="mt-1">
<i class="far fa-fw fa-clock text-secondary ml-1 mr-2"></i>Total time worked: <?php echo $ticket_total_reply_time; ?> <i class="far fa-fw fa-clock text-secondary ml-1 mr-2"></i>Total time worked: <?php echo $ticket_total_reply_time; ?>
@@ -613,13 +614,13 @@ if (isset($_GET['ticket_id'])) {
<!-- Asset card --> <!-- Asset card -->
<div class="card card-body card-outline card-dark mb-3"> <div class="card card-body card-outline card-dark mb-3">
<h4 class="text-secondary">Asset</h4> <h4 class="text-secondary">Asset</h4>
<?php if ($asset_id == 0) { ?> <?php if ($asset_id == 0) { ?>
<div> <div>
<a href="#" data-toggle="modal" data-target="#editTicketAssetModal<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-plus mr-2"></i>Add an Asset</a> <a href="#" data-toggle="modal" data-target="#editTicketAssetModal<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-plus mr-2"></i>Add an Asset</a>
</div> </div>
<?php } else { ?> <?php } else { ?>
<div> <div>
@@ -686,7 +687,7 @@ if (isset($_GET['ticket_id'])) {
<i class="fas fa-fw fa-ticket-alt"></i> <i class="fas fa-fw fa-ticket-alt"></i>
Ticket: <a href="ticket.php?ticket_id=<?php echo $service_ticket_id; ?>"><?php echo "$service_ticket_prefix$service_ticket_number" ?></a> <?php echo "on $service_ticket_created_at - <b>$service_ticket_subject</b> ($service_ticket_status)"; ?> Ticket: <a href="ticket.php?ticket_id=<?php echo $service_ticket_id; ?>"><?php echo "$service_ticket_prefix$service_ticket_number" ?></a> <?php echo "on $service_ticket_created_at - <b>$service_ticket_subject</b> ($service_ticket_status)"; ?>
</p> </p>
<?php <?php
} }
?> ?>
</div> </div>
@@ -699,13 +700,13 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
<?php } // End Ticket asset Count ?> <?php } // End Ticket asset Count ?>
<?php } // End if asset_id == 0 else ?> <?php } // End if asset_id == 0 else ?>
</div> </div>
<!-- End Asset card --> <!-- End Asset card -->
<!-- Vendor card --> <!-- Vendor card -->
<div class="card card-body card-outline card-dark mb-3"> <div class="card card-body card-outline card-dark mb-3">
<h4 class="text-secondary">Vendor</h4> <h4 class="text-secondary">Vendor</h4>
<?php if (empty($vendor_id)) { ?> <?php if (empty($vendor_id)) { ?>
@@ -784,14 +785,14 @@ if (isset($_GET['ticket_id'])) {
<i class="fas fa-fw fa-file-invoice mr-2"></i>Invoice Ticket <i class="fas fa-fw fa-file-invoice mr-2"></i>Invoice Ticket
</a> </a>
<?php } <?php }
if ($ticket_status !== "Closed") { ?> if ($ticket_status !== "Closed") { ?>
<a href="post.php?close_ticket=<?php echo $ticket_id; ?>" class="btn btn-secondary btn-block confirm-link"> <a href="post.php?close_ticket=<?php echo $ticket_id; ?>" class="btn btn-secondary btn-block confirm-link">
<i class="fas fa-fw fa-gavel mr-2"></i>Close Ticket <i class="fas fa-fw fa-gavel mr-2"></i>Close Ticket
</a> </a>
<?php } ?> <?php } ?>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,31 @@
<div class="modal" id="resetAllUserPassModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<div class="mb-4" style="text-align: center;">
<i class="far fas fa-10x fa-skull-crossbones text-danger mb-3 mt-3"></i>
<h2>Incident Response: Agent Password Reset</h2>
<br>
<div class="alert alert-danger" role="alert">
<b>This is a potentially destructive function.<br>It is intended to be used as part of a potential security incident.</b>
</div>
<h6 class="mb-4 text-secondary"><b>All ITFlow agent passwords will be reset and shown to you </b><i>(except yours - change yours first!)</i>.<br/><br/>You should communicate temporary passwords to agents out of band (e.g. via a phone call) and require they are changed ASAP.</h6>
<form action="post.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="row col-7 offset-4">
<div class="input-group">
<div class="input-group-prepend">
<input type="password" class="form-control" placeholder="Enter your account password to continue" name="admin_password" autocomplete="new-password" required>
</div>
</div>
</div>
<br>
<button class="btn btn-danger" type="submit" name="ir_reset_user_password"><i class="fas fa-fw fa-key mr-2"></i>Reset passwords</button>
</form>
</div>
<button type="button" class="btn btn-outline-secondary btn-lg px-5 mr-4" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>

View File

@@ -33,6 +33,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button> <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu"> <div class="dropdown-menu">
<!--<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#userInviteModal"><i class="fas fa-paper-plane mr-2"></i>Invite User</a>--> <!--<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#userInviteModal"><i class="fas fa-paper-plane mr-2"></i>Invite User</a>-->
<?php if ($num_rows[0] > 1) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#" data-toggle="modal" data-target="#resetAllUserPassModal"><i class="fas fa-skull-crossbones mr-2"></i>IR</a>
<?php } ?>
</div> </div>
</div> </div>
</div> </div>
@@ -197,4 +201,5 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
require_once("user_add_modal.php"); require_once("user_add_modal.php");
require_once("user_invite_modal.php"); require_once("user_invite_modal.php");
require_once("user_export_modal.php"); require_once("user_export_modal.php");
require_once("user_all_reset_password_modal.php");
require_once("footer.php"); require_once("footer.php");