b5ef4ac0cb
Admin-scoped users (answers: who can create a 'user' account, only super or also an admin within their own scope?): - New owner_admin_id column on users (migration 004). NULL means created by super (company-wide, previous behavior); otherwise scoped to that admin's own codes. - Users::addUser/editUser/deleteUser now allow an 'admin' session, but force type='user' and owner_admin_id to their own id regardless of submitted input. user.php/users.php open up to admins with a restricted UI (no type picker, listing limited to their own created users). - New qr_compute_scope_owner_id()/qr_apply_owner_scope()/qr_has_full_visibility() helpers in includes/security.php, replacing the ad-hoc type==='admin' checks in index.php, dynamic_qrcodes.php, static_qrcodes.php and bulk_action.php. A 'user' account created by an admin is now scoped to that admin's codes instead of seeing everything company-wide. Qr code storage hardening: images were served as plain static files under the document root with no auth check at all. Storage now lives outside the web root; qrcode_image.php and qrcode_zip_download.php gate access with the same permission model as the list pages, and the bulk zip download is bound to the session that generated it. PHP 8.4 + chillerlan/php-qrcode 6.0.1: bumped since this is a dockerized app, so the PHP version shipped doesn't matter to end users. Note: the 6.0.1 tag itself only requires PHP 8.2 - the earlier "needs 8.4" read was from an unpinned clone of master, which has since moved past the tag. Fixed along the way, surfaced by testing on 8.4: - The hardcoded Imagick build (an old pinned master commit, workaround for 3.7.0 being broken on PHP 8.3+) no longer compiles on 8.4. Imagick 3.8.1 is now a normal stable release, so the workaround is gone. - config.php had display_errors=On + error_reporting(E_ALL), so PHP 8.4's new deprecation notices got dumped straight into the response before session_start() could run, breaking login outright. Also an info-disclosure risk on its own. Now logged instead of displayed. - MysqliDb::insertMulti() had an implicit nullable parameter, now explicit. - includes/auth_validate.php redirected unauthenticated requests but never called exit(), so the rest of the script kept running. - Dockerfile.fpm was missing both git (needed to clone chillerlan/php-qrcode) and the imagick extension entirely. Also removes the unused sample qr code images that shipped in the original repo; storage now lives outside the document root so they were never going to be served again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
96 lines
3.0 KiB
PHP
96 lines
3.0 KiB
PHP
<?php
|
|
require_once 'includes/bootstrap.php';
|
|
require_once BASE_PATH . '/includes/auth_validate.php';
|
|
require_once BASE_PATH . '/lib/DynamicQrcode/DynamicQrcode.php';
|
|
|
|
if ($_SESSION['type'] === 'user' && empty($_SESSION['can_view_dynamic'] ?? null)) {
|
|
$_SESSION['failure'] = 'You are not allowed to view dynamic qr codes.';
|
|
header('Location: index.php');
|
|
exit;
|
|
}
|
|
|
|
$db = getDbInstance();
|
|
$dynamic_qrcode = new DynamicQrcode();
|
|
|
|
$select = array('id', 'id_owner', 'filename', 'identifier', 'link', 'qrcode', 'scan', 'state', 'created_at', 'updated_at');
|
|
$search_fields = array('filename', 'identifier', 'link');
|
|
require_once BASE_PATH . '/includes/search_order.php';
|
|
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? 1;
|
|
$db->pageLimit = 15;
|
|
|
|
// Scoped to one admin's own codes for an admin (or a 'user' created by that admin);
|
|
// full visibility for super and company-wide 'user' accounts.
|
|
qr_apply_owner_scope($db);
|
|
|
|
$rows = $db->arraybuilder()->paginate('dynamic_qrcodes', $page, $select);
|
|
$total_pages = $db->totalPages;
|
|
?>
|
|
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<title>Qrcode Generator</title>
|
|
<head>
|
|
<?php include './includes/head.php'; ?>
|
|
</head>
|
|
<body class="hold-transition sidebar-mini layout-fixed layout-navbar-fixed layout-footer-fixed">
|
|
<div class="wrapper">
|
|
<!-- Navbar -->
|
|
<?php include './includes/navbar.php'; ?>
|
|
<!-- /.navbar -->
|
|
|
|
<!-- Main Sidebar Container -->
|
|
<?php include './includes/sidebar.php'; ?>
|
|
<!-- /.Main Sidebar Container -->
|
|
|
|
<!-- Content Wrapper. Contains page content -->
|
|
<div class="content-wrapper">
|
|
<!-- Content Header -->
|
|
<div class="content-header">
|
|
<div class="container-fluid">
|
|
<div class="row mb-2">
|
|
|
|
<div class="col-sm-6">
|
|
<h1 class="m-0 text-dark">Dynamic Qr codes</h1>
|
|
</div><!-- /.col -->
|
|
|
|
<?php if ($_SESSION['type'] !== 'user'): ?>
|
|
<div class="col-sm-6">
|
|
<ol class="breadcrumb float-sm-right">
|
|
<li class="breadcrumb-item">
|
|
<a href="dynamic_qrcode.php" class="btn btn-success"><i class="fa fa-plus"></i> Add new</a>
|
|
</li>
|
|
</ol>
|
|
</div><!-- /.col -->
|
|
<?php endif; ?>
|
|
</div><!-- /.row -->
|
|
</div><!-- /.container-fluid -->
|
|
</div><!-- /.content-header -->
|
|
|
|
<!-- Flash message-->
|
|
<?php include BASE_PATH . '/includes/flash_messages.php'; ?>
|
|
<!-- /.Flash message-->
|
|
|
|
<!-- Filters -->
|
|
<?php $options = $dynamic_qrcode->setOrderingValues();
|
|
include BASE_PATH . '/forms/filters.php'; ?>
|
|
<!-- /.Filters-->
|
|
|
|
<!-- Main content -->
|
|
<section class="content">
|
|
<div class="container-fluid">
|
|
|
|
<!-- Table -->
|
|
<?php include BASE_PATH . '/forms/table_dynamic.php'; ?>
|
|
<!-- /.Table -->
|
|
|
|
</div><!-- /.container-fluid -->
|
|
</section>
|
|
</div><!-- /.content-wrapper -->
|
|
|
|
<!-- Footer and scripts -->
|
|
<?php include './includes/footer.php'; ?>
|
|
<!-- /.Footer and scripts -->
|
|
</body>
|
|
</html>
|