Commit Graph

172 Commits

Author SHA1 Message Date
dillard 7276744f32 Fase 3 feedback round 2: live color preview, bigger top icon, dashboard links
- Style preview now updates immediately when picking a color via the
  colorpicker widget. It sets the input value through jQuery's synthetic
  trigger(), which a native addEventListener('change', ...) never sees -
  bound the listener through jQuery instead so both native and
  colorpicker-driven changes refresh the preview.
- Icon-above-QR max height raised from 25% to 62.5% of QR height (~2.5x
  bigger per feedback); the existing 60%-width cap now becomes the
  practical limit for most icons. Verified generated QR still decodes.
- Dashboard's "Dynamic Qr codes" and "Static QR codes" info-boxes now link
  to their list pages. "Total qr codes"/"Total Scans" left as-is - no
  combined-list or scan-report page exists yet to link them to.
- Random-style button now has a "Randomize" label to match its row-mates
  (Load preset/Save as preset/Style preview), instead of an empty spacer.
2026-07-11 02:09:58 +02:00
dillard 23daf9c236 Fase 3 feedback round: style preview, icon upload, font choice, optional bitcoin amount, WPA3
- Default the Owner select to the creator's own account instead of "All", so
  superadmin-created codes no longer silently become visible to every admin
  (the underlying NULL-fallback sharing behavior for an explicit "All" choice
  is unchanged).
- Add a live color/precision/size preview swatch next to the preset picker.
- Let the frame text use a chosen DejaVu font + font size instead of a fixed
  GD bitmap font.
- Add an optional self-uploaded icon rendered above the qr code (not embedded
  in it, so scanability is unaffected).
- Make the Bitcoin qr amount optional; a standing wallet address is useful
  without forcing a one-off amount per code.
- Add a WPA3 option to the WiFi qr encryption select.
- Fix a real bug surfaced while testing the preview/style JS: qrcode_options.php
  was included once per static qr type (16 times on one page) and each
  inclusion re-executed <script src="qrcode-style-tools.js">, so every button
  click fired once per type - e.g. saving one preset wrote 16 duplicate rows,
  and every tab except the first ("Text") had dead random-style/preset
  buttons since only the first DOM match ever got a listener. Moved the
  script include to load once per page and rewrote the JS to scope every
  lookup to the triggering element's own tab-pane/form instead of relying on
  getElementById's first-match behavior.
2026-07-09 23:11:36 +02:00
dillard c3c6f167e0 Fase 3 priority 2: presets, random style, qr scanner, PWA
Preset system: qr_presets table (migration 005) plus a presets.php AJAX
endpoint (list/save/delete, CSRF-protected, scoped to the logged-in user's
own id - presets are personal, never shared across accounts). UI/JS lives in
dist/js/qrcode-style-tools.js.

Random style button: client-side only, fills foreground/background with a
random hex color pair (playful randomize, no contrast/scannability
guarantee).

Qr scanner (scan_qrcode.php): camera or image upload, decoded entirely
client-side via html5-qrcode (CDN, pinned to 2.3.8).

PWA: manifest.json + service-worker.js, icons generated from the existing
DynamicQRCode_Original.png glyph. The service worker only caches static
assets (css/js/images) and deliberately never touches PHP pages, since those
carry CSRF tokens and session-specific content that must never be cached.

Fixes a gap found while testing: qrcode_options.php is only a shared partial
for the static qr forms - the dynamic qr form (form_dynamic_add.php) has its
own separate copy of the foreground/background/level/size/filename/format
fields (pre-existing structure, not something introduced here). That meant
frame_text and the new preset/random-style UI never showed up on the
dynamic qr page. Added the same fields there too, verified with a dynamic qr
plus frame text (150x180px, the expected +30px padding).
2026-07-09 00:49:45 +02:00
dillard 4e9fed755c Fase 3 v1: new qr types, svg export, clipboard, frame text, batch CSV
New static qr types:
- App Link: Android intent:// links (with package + optional browser
  fallback) or a generic custom-scheme URI. iOS Universal Links need no
  special encoding (they're just plain https:// URLs).
- Bluetooth: device name + MAC address. Purely informational, since unlike
  WIFI:/vCard there's no OS-native "scan to pair" convention.

SVG export: already worked (format whitelist/dropdown existed since Fase 1),
verified rather than reimplemented.

Copy-to-clipboard button next to the download button on both qr list tables,
using the Clipboard API against a fetched blob.

Optional frame text label rendered below the qr code via GD after
generation (raster formats only, no-op for svg/eps).

Batch CSV upload (batch_qrcode.php): filename,link rows create dynamic qr
codes with sane defaults, downloadable as a zip. Required refactoring
Qrcode-intchil.php's generation path (previously always redirected/exited
via failure()/success(), which can't run in a loop) into a private
renderAndStore() that throws instead, shared by addQrcode() and the new
addQrcodeBatch(). Qrcode.php's addQrcodeBatch() is a separate, deliberately
duplicated implementation instead, since its generation logic is small
enough that duplication carries less risk than refactoring the working
external-API code path.
2026-07-09 00:03:01 +02:00
dillard 6387d24846 Admin-scoped user accounts, secure qr code storage, PHP 8.4 upgrade
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.
2026-07-08 20:38:58 +02:00
dillard 52c9f65c61 Fase 2: read-only user role with per-category view toggles
Adds a third account type 'user' alongside super/admin: no create/edit/delete
rights on qr codes, view access to dynamic/static lists gated per-account by
two admin-controlled toggles (can_view_static, can_view_dynamic), and always
full visibility into the dashboard/reports regardless of those toggles.

- New columns can_view_static/can_view_dynamic on users (migrations/003)
- Users class + form_users.php: 'user' type option with the two toggles
- Access control: dynamic_qrcode.php/static_qrcode.php/bulk_action.php reject
  all mutations for type=user; dynamic_qrcodes.php/static_qrcodes.php enforce
  the view toggle and show all codes (no owner scoping, since 'user' owns none)
- Sidebar and list tables hide add/edit/delete/bulk UI for the read-only role
- index.php dashboard stats are unscoped for both 'super' and 'user'
2026-07-08 16:37:25 +02:00
dillard 3afe3b7698 Security hardening: CSRF, rate limiting, session/password policy, audit log
Fixes critical pre-existing issues found during review: bulk_action.php had no
auth check at all (unauthenticated download/delete of any qrcode) and built a
table name from unwhitelisted user input (SQL injection); the QR generator
classes wrote files from unvalidated filename/format, allowing path traversal
and arbitrary file writes. Also pins chillerlan/php-qrcode to 5.0.5 since
master now requires PHP 8.4, breaking the PHP 8.3 build.

- CSRF tokens on all POST forms and the bulk_action.php JSON endpoint
- Login rate limiting (5 attempts / 15 min) via new login_attempts table
- Hardened sessions: httponly/samesite cookies, 30 min idle timeout,
  session regeneration on login
- Forced password change for the default superadmin/superadmin account
- Server-side validation in Users/DynamicQrcode/Qrcode classes
- Audit log table for auth, user, and qrcode actions
- Checked-in db schema (db/init.sql, migrations/) instead of relying on an
  opaque prebuilt db image
- Production docker-compose with Nginx + php-fpm instead of the PHP dev server
v0.8
2026-07-08 15:00:33 +02:00
Giandonato Inverso 8db3158239 Remove unnecessary extra information from documentation 2025-09-02 21:56:03 +02:00
Giandonato Inverso b3b799819e Delete support section from index.html 2025-09-02 21:53:41 +02:00
Giandonato Inverso f89b39bde3 Remove donation button from README 2025-09-02 21:52:03 +02:00
Giandonato Inverso acb154502b Merge pull request #144 from CLAlberto/master
fix(read.php): replace deprecated FILTER_SANITIZE_STRING for PHP 8.3 …
2025-05-08 08:56:07 +02:00
CLAlberto f24a7086ab fix(read.php): replace deprecated FILTER_SANITIZE_STRING for PHP 8.3 compatibility
### Problem

The usage of `FILTER_SANITIZE_STRING` in `read.php` causes a deprecation warning in PHP 8.1 and breaks functionality entirely in PHP 8.3, as the constant was removed.

### Solution

This commit replaces:
```php
filter_input(INPUT_GET, 'id', FILTER_SANITIZE_STRING);



with a safer and future-proof alternative:

$id = filter_input(INPUT_GET, 'id', FILTER_UNSAFE_RAW);
$id = trim(strip_tags($id));


> _Thanks for maintaining this project! Happy to contribute._ 😊
2025-05-06 16:16:22 +02:00
Giandonato Inverso 2f0c879158 Merge pull request #143 from angelosleebos/patch-1
Make environment variables compatible for other platforms
2025-04-14 12:19:34 +02:00
Giandonato Inverso 2ce6a03921 Merge pull request #142 from rafinou62/patch-1
Update read.php prevent SQL Injection & XSS attacks
2025-04-14 12:18:32 +02:00
Angelo Sleebos 40ec07fbb1 Make environment variables compatible for other platforms
Make environment variables compatible for other platforms
2025-04-07 01:11:17 +02:00
Raphaël Wanecque 6cfbc4a759 Update read.php prevent SQL Injection & XSS attacks 2025-03-26 17:04:33 +01:00
giandonato.inverso@edempg.it 3ee79bfab7 edit demo url 2025-03-22 15:51:02 +01:00
giandonato.inverso@edempg.it a2fdf79491 config rollback 2025-03-20 23:38:55 +01:00
giandonato.inverso@edempg.it 236d7342d3 Merge remote-tracking branch 'origin/master' 2025-03-19 23:40:50 +01:00
giandonato.inverso@edempg.it 1f3110b26e bug fix Class Qrcode not found 2025-03-19 23:40:36 +01:00
Giandonato Inverso 8b24fd839d Merge pull request #136 from MickGe/patch-1
add cookies secure flags
2025-02-09 16:16:53 +01:00
MickGe 011e91e3d0 add cookies secure flags 2025-02-07 11:35:24 +01:00
giandonato.inverso@edempg.it 737ceca97b updated readme and docs 2025-01-21 22:41:14 +01:00
giandonato.inverso@edempg.it b4b42ddb29 updated readme 2025-01-12 23:50:15 +01:00
giandonato.inverso@edempg.it 3ca4163715 Local setup eliminated and documentation updated 2025-01-12 23:48:49 +01:00
giandonato.inverso@edempg.it c5f1b0d74f Merge remote-tracking branch 'origin/master' 2025-01-12 19:48:31 +01:00
Giandonato Inverso d825f597b8 Merge pull request #130 from Shineson1001/feature/129-QRCodeGeneratorSwitch
🐛 Global switch for the QR code generator (#129)
2025-01-02 12:04:55 +01:00
Shine 850f5e5c52 🐛 Global switch for the QR code generator (#129) 2024-12-31 20:48:56 +01:00
giandonato.inverso@edempg.it c46dae55ce Revert "Revert "Instead using external API (api.qrserver.com) .. use chillerlan/php-qrcode""
This reverts commit 4d33cf5379.
2024-12-23 18:52:11 +01:00
giandonato.inverso@edempg.it 4d33cf5379 Revert "Instead using external API (api.qrserver.com) .. use chillerlan/php-qrcode"
This reverts commit 6d42677732.
2024-12-23 18:49:05 +01:00
Giandonato Inverso a1bd583ad3 Merge pull request #128 from Shineson1001/feature/116-EventIncorrectTimeZone
🐛 Event: Incorrect Time Zone
2024-12-20 20:02:32 +01:00
Shine 597afbb1fe 🐛 Event: Incorrect Time Zone
- Add "Time zone" input field.
- 24-Hour time format.
- Set Min-Year and Max-Year dynamically
2024-12-19 22:34:42 +01:00
Giandonato Inverso 5028541bfd Merge pull request #127 from Shineson1001/feature/88-SelfHostedQRCodeGenerator
Instead using external API (api.qrserver.com) .. use chillerlan/php-qrcode
2024-12-15 16:35:29 +01:00
Shine 6d42677732 Instead using external API (api.qrserver.com) .. use chillerlan/php-qrcode 2024-12-15 14:36:39 +01:00
Giandonato Inverso 1499f06c71 Merge pull request #126 from Shineson1001/feature/2FA-QRCodes
Add 2FA QR Code
2024-12-14 09:17:50 +01:00
Shine 058277c0fc Add 2FA QR Code
Save your 2FA secrets to QR-Code.
2024-12-13 23:42:57 +01:00
Giandonato Inverso a426d45be1 available plugins 2024-10-20 16:32:58 +02:00
Giandonato Inverso 3f7ac0bce1 Update README.md 2024-10-20 11:07:12 +02:00
giandonato.inverso@edempg.it 9548a6d73a bug fix in helpers.php 2024-04-21 12:55:03 +02:00
giandonato.inverso@edempg.it 2715f2106c edit readme 2024-04-21 12:38:35 +02:00
giandonato.inverso@edempg.it e43e8f774e bug fix 2024-04-18 20:54:04 +02:00
giandonato.inverso@edempg.it acebfdd708 fix in bulk action 2024-04-18 20:44:22 +02:00
giandonato.inverso@edempg.it 005c67d721 readme 2024-04-18 20:35:04 +02:00
giandonato.inverso@edempg.it 9f2d14abf8 bug fix in read.php, bump version in footer, NEW: bulk delete 2024-04-18 20:33:20 +02:00
giandonato.inverso@edempg.it eba0ebbba7 bug fix database prefix in Qrcode class 2024-03-11 15:43:16 +01:00
giandonato.inverso@edempg.it 068ddebd35 bug fix bulk download 2024-03-04 14:36:18 +01:00
Giandonato Inverso d0d3daf7db Merge pull request #94 from tranmh/xss_static_qrcode
Fix Security: Stored Cross Site Scripting for static QR code
2024-03-01 09:58:29 +01:00
Minh Cuong Tran 92eb66fb35 Fix Security: Stored Cross Site Scripting for static QR code, see https://github.com/giandonatoinverso/PHP-Dynamic-Qr-code/issues/93 2024-03-01 08:03:31 +01:00
Giandonato Inverso b85f98e16d Merge pull request #92 from tranmh/fix_remove_DATABASE_PREFIX_for_getOne
Inconsistency of using DATABASE_PREFIX with getOne()
2024-02-29 00:25:17 +01:00
Minh Cuong Tran a7953f05bb Inconsistency of using DATABASE_PREFIX with getOne() 2024-02-28 16:56:39 +01:00