mirror of
https://github.com/itflow-org/itflow
synced 2026-11-11 07:01:16 +00:00
227 lines
13 KiB
PHP
227 lines
13 KiB
PHP
<?php
|
|
|
|
/*
|
|
* A shared link's quick look (functions/share.php) - what it is, who it was
|
|
* for and who made it, what it asks for before it opens, where it is now, and
|
|
* everything that happened to it from the audit log: opened when, from which
|
|
* address and browser, wrong passphrases, codes sent, turned off.
|
|
*
|
|
* For a request a client has answered, what they sent - read through the
|
|
* vault, and logged - with Save to credentials and Discard.
|
|
*/
|
|
|
|
require_once '../../../includes/modal_header.php';
|
|
|
|
$item_id = intval($_GET['id'] ?? 0);
|
|
$row = shareRow($item_id);
|
|
if (!$row || !shareCanSee($row['item_type'])) {
|
|
exit(json_encode(['error' => 'That link no longer exists.']));
|
|
}
|
|
$client_id = intval($row['item_client_id']);
|
|
enforceClientAccess();
|
|
|
|
$types = shareTypes();
|
|
$type = $row['item_type'];
|
|
$type_info = $types[$type] ?? ['label' => $type, 'icon' => 'fa-share-alt'];
|
|
$state = shareState($row);
|
|
$is_open = in_array($state, ['active', 'waiting'], true);
|
|
$can_end = shareCanMake($type);
|
|
$protection = shareProtection($row);
|
|
$history = shareHistory($row);
|
|
|
|
// What a client sent back - only for whoever may make credentials, and read through the vault
|
|
$received = null;
|
|
if ($state === 'received' && lookupUserPermission('module_credential') >= 2) {
|
|
$received = shareRequestOpen($row);
|
|
if (is_array($received)) {
|
|
logAudit('Share', 'Read', "$session_name looked at the login sent back for " . escapeSql(shareName($row)), $client_id, $item_id);
|
|
}
|
|
}
|
|
|
|
$history_icons = [
|
|
'Create' => 'fa-plus-circle', 'Open' => 'fa-eye', 'View' => 'fa-eye', 'Download' => 'fa-download', 'Receive' => 'fa-inbox',
|
|
'Code' => 'fa-envelope', 'Verify' => 'fa-check', 'Fail' => 'fa-times-circle text-danger', 'Lock' => 'fa-lock text-danger',
|
|
'Destroy' => 'fa-fire', 'Revoke' => 'fa-unlink', 'Save' => 'fa-save', 'Discard' => 'fa-trash', 'Read' => 'fa-key',
|
|
];
|
|
|
|
ob_start();
|
|
|
|
?>
|
|
|
|
<div class="modal-header bg-dark" data-bs-theme="dark">
|
|
<div class="d-flex align-items-center gap-3 min-w-0">
|
|
<span class="itflow-link-icon" aria-hidden="true"><i class="fas fa-fw <?= $type_info['icon'] ?>"></i></span>
|
|
<div class="min-w-0">
|
|
<h5 class="modal-title d-flex flex-wrap align-items-center column-gap-2">
|
|
<span class="fw-semibold text-break"><?= escapeHtml(shareName($row)) ?></span>
|
|
<?= shareStateBadge($row) ?>
|
|
</h5>
|
|
<div class="small text-body-secondary mt-1"><?= escapeHtml($type_info['label']) ?> · <?= escapeHtml($row['client_name']) ?></div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
|
|
<div class="row g-2 mb-3">
|
|
<div class="col-sm-6">
|
|
<div class="itflow-glance-item" title="Who it is for">
|
|
<i class="fas fa-fw fa-user"></i>
|
|
<span class="text-break"><?= trim((string) $row['item_recipient']) !== '' ? escapeHtml($row['item_recipient']) : '<span class="text-body-secondary">Anyone with the link</span>' ?></span>
|
|
</div>
|
|
<div class="itflow-glance-item" title="Made">
|
|
<i class="fas fa-fw fa-plus-circle"></i>
|
|
<span>Made <?= timeAgo($row['item_created_at']) ?><?= $row['creator_name'] !== null ? ' by ' . escapeHtml($row['creator_name']) : '' ?></span>
|
|
</div>
|
|
<div class="itflow-glance-item" title="<?= $row['item_received_at'] ? 'Sent back' : 'Works until' ?>">
|
|
<i class="fas fa-fw fa-<?= $row['item_received_at'] ? 'inbox' : 'clock' ?>"></i>
|
|
<?php if ($row['item_received_at']) { ?>
|
|
<span>Sent back <?= escapeHtml(date('M j, Y g:i A', strtotime($row['item_received_at']))) ?></span>
|
|
<?php } else { ?>
|
|
<span><?= $is_open ? 'Works until ' : 'Was to work until ' ?><?= escapeHtml(date('M j, Y g:i A', strtotime($row['item_expire_at']))) ?></span>
|
|
<?php } ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="itflow-glance-item" title="Opened">
|
|
<i class="fas fa-fw fa-eye"></i>
|
|
<span><?= escapeHtml(shareViewsText($row)) ?><?= $row['item_last_viewed_at'] ? ' <span class="text-body-secondary">· last ' . timeAgo($row['item_last_viewed_at']) . '</span>' : '' ?></span>
|
|
</div>
|
|
<div class="itflow-glance-item" title="Before it opens">
|
|
<i class="fas fa-fw fa-shield-alt"></i>
|
|
<span>
|
|
<?= ['passphrase' => 'Needs a passphrase', 'code' => 'Needs a code emailed to the recipient', '' => 'Opens with the link alone'][$protection] ?>
|
|
<?php if (intval($row['item_failed_attempts'])) { ?>
|
|
<span class="text-danger-emphasis">· <?= intval($row['item_failed_attempts']) ?> wrong</span>
|
|
<?php } ?>
|
|
</span>
|
|
</div>
|
|
<div class="itflow-glance-item" title="Notifications">
|
|
<i class="fas fa-fw fa-bell<?= $row['item_notify'] ? '' : '-slash' ?>"></i>
|
|
<span><?= $row['item_notify'] ? ($row['creator_name'] !== null ? escapeHtml($row['creator_name']) . ' is told when it is ' . ($type === 'Request' ? 'answered' : 'opened') : 'Everyone is told when it is opened') : 'Nobody is told when it is opened' ?></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($row['item_ended_at']) { ?>
|
|
<div class="small text-body-secondary mb-3">
|
|
<i class="fas fa-fw fa-info-circle me-1"></i><?= escapeHtml(shareStates()[$state][0]) ?> <?= timeAgo($row['item_ended_at']) ?><?= $row['ender_name'] !== null ? ' by ' . escapeHtml($row['ender_name']) : '' ?>.
|
|
<?= in_array($state, ['locked', 'destroyed'], true) ? ($state === 'locked' ? 'Too many wrong passphrases or codes.' : 'The person it was for destroyed it once they had what they needed.') : '' ?>
|
|
</div>
|
|
<?php } ?>
|
|
|
|
<?php if (trim((string) $row['item_note']) !== '') { ?>
|
|
<div class="small text-body-secondary fw-semibold text-uppercase mb-1">Note for them</div>
|
|
<div class="small mb-3"><?= nl2br(escapeHtml($row['item_note'])) ?></div>
|
|
<?php } ?>
|
|
|
|
<?php if ($state === 'received') { ?>
|
|
<div class="card border-warning-subtle mb-3">
|
|
<div class="card-header bg-warning-subtle py-2 small fw-semibold">
|
|
<i class="fas fa-inbox me-2"></i>Sent back <?= timeAgo($row['item_received_at']) ?> - save it to the client's credentials
|
|
</div>
|
|
<div class="card-body py-2">
|
|
<?php if ($received === false) { ?>
|
|
<div class="small text-danger-emphasis"><i class="fas fa-lock me-2"></i>Your vault session has expired, so it cannot be read - sign out and back in, then open this again.</div>
|
|
<?php } elseif (is_array($received)) { ?>
|
|
<dl class="row small mb-0">
|
|
<?php if (trim((string) ($received['uri'] ?? '')) !== '') { ?>
|
|
<dt class="col-sm-3 fw-normal text-body-secondary">Website</dt>
|
|
<dd class="col-sm-9 text-break"><?= escapeHtml($received['uri']) ?></dd>
|
|
<?php } ?>
|
|
<dt class="col-sm-3 fw-normal text-body-secondary">Username</dt>
|
|
<dd class="col-sm-9 d-flex align-items-center min-w-0">
|
|
<span class="font-monospace text-break"><?= trim((string) ($received['username'] ?? '')) !== '' ? escapeHtml($received['username']) : '-' ?></span>
|
|
<?php if (trim((string) ($received['username'] ?? '')) !== '') { ?><button type="button" class="itflow-copy clipboardjs" title="Copy" data-clipboard-text="<?= escapeHtml($received['username']) ?>"><i class="far fa-copy"></i></button><?php } ?>
|
|
</dd>
|
|
<dt class="col-sm-3 fw-normal text-body-secondary">Password</dt>
|
|
<dd class="col-sm-9">
|
|
<?php if (($received['password'] ?? '') !== '') { ?>
|
|
<div class="input-group input-group-sm">
|
|
<input type="password" class="form-control font-monospace" value="<?= escapeHtml($received['password']) ?>" readonly data-toggle="password" aria-label="Password">
|
|
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
|
|
<button type="button" class="btn btn-outline-secondary clipboardjs" title="Copy password" data-clipboard-text="<?= escapeHtml($received['password']) ?>"><i class="far fa-fw fa-copy"></i></button>
|
|
</div>
|
|
<?php } else { ?>
|
|
-
|
|
<?php } ?>
|
|
</dd>
|
|
<?php if (trim((string) ($received['otp'] ?? '')) !== '') { ?>
|
|
<dt class="col-sm-3 fw-normal text-body-secondary">2FA secret</dt>
|
|
<dd class="col-sm-9"><span class="text-body-secondary">Sent - saved with the credential</span></dd>
|
|
<?php } ?>
|
|
<?php if (trim((string) ($received['note'] ?? '')) !== '') { ?>
|
|
<dt class="col-sm-3 fw-normal text-body-secondary">Their note</dt>
|
|
<dd class="col-sm-9"><?= nl2br(escapeHtml($received['note'])) ?></dd>
|
|
<?php } ?>
|
|
</dl>
|
|
<?php } elseif (lookupUserPermission('module_credential') < 2) { ?>
|
|
<div class="small text-body-secondary">Someone who can add credentials for this client can save it.</div>
|
|
<?php } else { ?>
|
|
<div class="small text-body-secondary">There is nothing to read - it may have been saved or discarded already.</div>
|
|
<?php } ?>
|
|
</div>
|
|
<?php if (is_array($received) && $can_end) { ?>
|
|
<div class="card-footer d-flex gap-2 py-2">
|
|
<form action="post.php" method="post" class="m-0">
|
|
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
|
<input type="hidden" name="item_id" value="<?= $item_id ?>">
|
|
<button type="submit" name="share_request_save" value="1" class="btn btn-sm btn-primary text-bold"><i class="fas fa-save me-2"></i>Save to credentials</button>
|
|
</form>
|
|
<a class="btn btn-sm btn-outline-danger confirm-link" href="post.php?share_request_discard=<?= $item_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" data-confirm-text="What they sent is deleted without being saved."><i class="fas fa-trash me-2"></i>Discard</a>
|
|
</div>
|
|
<?php } ?>
|
|
</div>
|
|
<?php } ?>
|
|
|
|
<div class="small text-body-secondary fw-semibold text-uppercase mb-1">History</div>
|
|
<?php if ($history) { ?>
|
|
<ul class="list-unstyled small mb-0">
|
|
<?php foreach ($history as $entry) {
|
|
$icon = $history_icons[$entry['log_action']] ?? 'fa-circle';
|
|
$where = [];
|
|
if ($entry['user_name'] === null && $entry['log_ip'] !== '') {
|
|
$where[] = escapeHtml($entry['log_ip']);
|
|
}
|
|
if ($entry['user_name'] === null && $entry['log_user_agent'] !== '') {
|
|
// "Chrome on Windows" - as much of it as the browser said
|
|
$browser = trim(strip_tags(getWebBrowser($entry['log_user_agent'])));
|
|
$os = trim(strip_tags(getOS($entry['log_user_agent'])));
|
|
$device = implode(' on ', array_filter([$browser, $os], function ($part) { return $part !== '-'; }));
|
|
if ($device !== '') {
|
|
$where[] = escapeHtml($device);
|
|
}
|
|
} ?>
|
|
<li class="d-flex gap-2 py-1 border-bottom">
|
|
<i class="fas fa-fw <?= $icon ?> text-body-secondary mt-1" aria-hidden="true"></i>
|
|
<span class="flex-grow-1 min-w-0">
|
|
<?= escapeHtml($entry['log_description']) ?>
|
|
<?php if ($where) { ?><span class="d-block text-body-secondary"><?= implode(' · ', $where) ?></span><?php } ?>
|
|
</span>
|
|
<span class="text-body-secondary text-nowrap" title="<?= escapeHtml($entry['log_created_at']) ?>"><?= timeAgo($entry['log_created_at']) ?></span>
|
|
</li>
|
|
<?php } ?>
|
|
</ul>
|
|
<?php } else { ?>
|
|
<div class="small text-body-secondary">Nothing yet.</div>
|
|
<?php } ?>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<?php $item_link = shareItemMenuLink($row); ?>
|
|
<?php if ($item_link) { ?>
|
|
<div class="me-auto"><?= str_replace('dropdown-item', 'btn btn-outline-secondary', $item_link) ?></div>
|
|
<?php } ?>
|
|
<?php if ($can_end && $is_open) { ?>
|
|
<a class="btn btn-outline-danger confirm-link" href="post.php?share_revoke=<?= $item_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" data-confirm-text="The link stops working straight away.">
|
|
<i class="fas fa-unlink me-2"></i><?= $type === 'Request' ? 'Cancel the request' : 'Turn off' ?>
|
|
</a>
|
|
<?php } ?>
|
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Close</button>
|
|
</div>
|
|
|
|
<?php
|
|
require_once '../../../includes/modal_footer.php';
|