['label' => 'All', 'where' => ''], 'starred' => ['label' => 'Starred', 'icon' => 'fa-star', 'where' => 'c.credential_favorite = 1'], 'otp' => ['label' => 'With 2FA', 'icon' => 'fa-clock', 'where' => "c.credential_otp_secret <> ''"], 'nootp' => ['label' => 'No 2FA', 'icon' => 'fa-unlock', 'where' => "(c.credential_otp_secret IS NULL OR c.credential_otp_secret = '')"], 'due' => ['label' => "Not changed in $rotate_days days", 'icon' => 'fa-history', 'where' => "(c.credential_password_changed_at IS NULL OR c.credential_password_changed_at < NOW() - INTERVAL $rotate_days DAY)"], 'shared' => ['label' => 'Shared', 'icon' => 'fa-share-alt', 'where' => "c.credential_id IN (SELECT item_related_id FROM shared_items WHERE item_type = 'Credential' AND " . shareOpenSql() . ")"], ]; $show = isset($shows[$_GET['show'] ?? '']) ? ($_GET['show'] ?? '') : ''; $show_query = $shows[$show]['where'] ? 'AND ' . $shows[$show]['where'] : ''; // Only these sort - filter_header.php will hand through any lowercase word, and // an unknown column takes the page down with a mysqli exception $sortable_columns = ['credential_name', 'credential_uri', 'credential_password_changed_at', 'credential_accessed_at', 'client_name', 'credential_created_at']; if (!in_array($sort, $sortable_columns, true)) { $sort = 'credential_name'; } $sort_column = $sort === 'client_name' ? 'client_name' : "c.$sort"; $search_query = "AND (c.credential_name LIKE '%$q%' OR c.credential_description LIKE '%$q%' OR c.credential_uri LIKE '%$q%' OR c.credential_uri_2 LIKE '%$q%' OR c.credential_note LIKE '%$q%' OR client_name LIKE '%$q%' OR asset_name LIKE '%$q%' OR contact_name LIKE '%$q%' OR c.credential_id IN (SELECT credential_id FROM credential_tags JOIN tags USING (tag_id) WHERE tag_name LIKE '%$q%'))"; $scope_query = clientScopeSql('credential_client_id'); $sql = mysqli_query( $mysqli, "SELECT SQL_CALC_FOUND_ROWS c.credential_id, c.credential_name, c.credential_description, c.credential_uri, c.credential_uri_2, c.credential_username, c.credential_otp_secret, c.credential_favorite, c.credential_archived_at, c.credential_password_changed_at, c.credential_accessed_at, c.credential_client_id, client_name, contact_id, contact_name, contact_photo, contact_archived_at, asset_id, asset_name, asset_type, asset_archived_at FROM credentials c LEFT JOIN clients ON client_id = credential_client_id LEFT JOIN contacts ON contact_id = credential_contact_id AND contact_client_id = credential_client_id LEFT JOIN assets ON asset_id = credential_asset_id AND asset_client_id = credential_client_id WHERE $archive_query $tag_query $search_query $location_query $show_query $scope_query $client_query ORDER BY c.credential_favorite DESC, $sort_column $order, c.credential_name ASC LIMIT $record_from, $record_to" ); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $credentials = []; while ($row = mysqli_fetch_assoc($sql)) { $credentials[intval($row['credential_id'])] = $row; } // Tags, links and share links for the whole page at once, not per row $credentials_tags = tagsForRecords('credential', array_keys($credentials)); $credentials_links = credentialLinks(array_keys($credentials)); $credentials_shares = credentialShares(array_keys($credentials)); // How many of each, for the pills - everything in scope, before the pill itself $counts = ['' => 0]; $count_sql = []; foreach ($shows as $key => $s) { $count_sql[] = $key === '' ? 'COUNT(*)' : "COALESCE(SUM({$s['where']}), 0)"; } $row = mysqli_fetch_row(mysqli_query($mysqli, "SELECT " . implode(', ', $count_sql) . " FROM credentials c LEFT JOIN clients ON client_id = credential_client_id LEFT JOIN contacts ON contact_id = credential_contact_id AND contact_client_id = credential_client_id LEFT JOIN assets ON asset_id = credential_asset_id AND asset_client_id = credential_client_id WHERE $archive_query $tag_query $search_query $location_query $scope_query $client_query")); foreach (array_keys($shows) as $i => $key) { $counts[$key] = intval($row[$i]); } $filter_url = function ($changes) use ($client_url) { $params = array_merge($_GET, $changes); unset($params['page']); return '?' . http_build_query(array_filter($params, function ($v) { return $v !== '' && $v !== null; })); }; ?>

Credentials

Archived
text-nowrap table-light"> $row) { $row_client_id = intval($row['credential_client_id']); $credential_name = escapeHtml($row['credential_name']); $credential_description = escapeHtml($row['credential_description']); $credential_favorite = intval($row['credential_favorite']); $credential_archived_at = escapeHtml($row['credential_archived_at']); $credential_tags = $credentials_tags[$credential_id] ?? []; $credential_links = $credentials_links[$credential_id] ?? []; $credential_shares = $credentials_shares[$credential_id] ?? []; $has_otp = trim((string) $row['credential_otp_secret']) !== ''; $age = credentialAge($row['credential_password_changed_at']); $quick_url = "modals/credential/credential.php?id=$credential_id"; ?>
Credential Login For Changed Client
Shared Archived
2) { ?> + more -
-' ?>
Used
'credentials', 'icon' => 'fa-key', 'filtered' => $q || $tag_query, 'views' => ['show'], 'view' => emptyStatePill($shows, $show, '', ['nootp', 'due']), 'text' => 'The logins for their systems, encrypted in the vault.', 'actions' => $can_edit ? array_merge( [['label' => 'New Credential', 'modal' => "modals/credential/credential_add.php?$client_url", 'size' => 'lg']], $client_url ? [['label' => 'Import', 'modal' => "modals/credential/credential_import.php?$client_url", 'icon' => 'fa-upload']] : [] ) : [], ]; require_once "../includes/filter_footer.php"; ?>