Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
246 commits
Select commit Hold shift + click to select a range
d1e1609
Right — same commit or separate, here's the combined version covering…
johnnyq Jul 5, 2026
78c3dd0
Remove Dig and Whois binary requirements, revert fetchUpdates function
johnnyq Jul 5, 2026
47a5825
OAUTH Send Invoice Fix: was reading smtp host var needed to read smtp…
johnnyq Jul 7, 2026
de6d2b1
OAUTH Send Quote Fix: was reading smtp host var needed to read smtp p…
johnnyq Jul 7, 2026
ae5c9fe
Mail Parser: Add logic when creating ITFlow folder to determine if th…
johnnyq Jul 8, 2026
c01645c
Expense: On create enforce client Access only if Client is selected
johnnyq Jul 8, 2026
68f705b
Set EnforceClientAccess Perms throughout expenses, modals and post al…
johnnyq Jul 9, 2026
317fe91
Add Missing clientEnforcement in various modals, already handled on P…
johnnyq Jul 9, 2026
21328c2
clientEnforcement on Recurring Invoices and payments listings
johnnyq Jul 9, 2026
fc59481
Enforce Client Access in client selectbox
johnnyq Jul 9, 2026
d2026a4
Add Client to top of the modals trips, ticket, recurring ticket, invo…
johnnyq Jul 9, 2026
7ba1571
Revert Billable placement in tickets, create CONTRIBUTING.md file
johnnyq Jul 10, 2026
8da3a10
Rename plugins to libs and update all file references
johnnyq Jul 10, 2026
0f0aa89
Bump ImapEngine from 1.25.0 to 1.25.1
johnnyq Jul 10, 2026
91e9f60
Client Overview Side Nav: Only shows counts to the user who has permi…
johnnyq Jul 13, 2026
fe7e9b2
Main Side Nav: Only shows counts to the user who has permission to see
johnnyq Jul 13, 2026
95441dc
Show 7 Characters of client name in client side nav instead of Abbrev…
johnnyq Jul 13, 2026
b81e57d
Show Invoice Stats in Invoice only for user permissable clients
johnnyq Jul 13, 2026
79032de
Certificates: Allow to search by description
johnnyq Jul 14, 2026
c1447f5
Bump TinyMCE from 8.6.0 to 8.7.0
johnnyq Jul 14, 2026
a2a96f9
Removed unused legacy functions and split the functions into their ow…
johnnyq Jul 14, 2026
29bea95
Removed the last of legacy validate functions and replaced with the n…
johnnyq Jul 14, 2026
bf0d799
Remove old function comment
johnnyq Jul 14, 2026
5eb9f6b
Fix weak RNG in key32gen (TOTP secret generation)
johnnyq Jul 14, 2026
d62b6e2
Update comment
johnnyq Jul 14, 2026
7bc47a5
Replace Function nullable_htmlentities() with just escapeHtml() and u…
johnnyq Jul 14, 2026
b57ddc0
Replace Function sanitizeInput() with just escapeSql() and update all…
johnnyq Jul 14, 2026
8de3cd3
Replace Function key32gen() with generateTotpSecret()
johnnyq Jul 14, 2026
31cc3f3
Replace Function strtoAZaz09() with toAlphanumeric()
johnnyq Jul 14, 2026
29a0b3e
Replace Function fetchUpdates() with checkForUpdates()
johnnyq Jul 14, 2026
f1836c7
Replace Function logAction() with logAudit()
johnnyq Jul 14, 2026
b887303
Rename Functions: flash_alert, sanitizeFilename and display_folder_op…
johnnyq Jul 14, 2026
9d540f4
Replace Function customAction() with triggerCustomAction()
johnnyq Jul 14, 2026
8f824a1
Replace Function shortenClient() with shortenClientName()
johnnyq Jul 14, 2026
52b5063
Replace Function getDomainRecords() with getDnsRecords()
johnnyq Jul 14, 2026
21a23e7
Replace Function getSSL() with getSslCertificate()
johnnyq Jul 14, 2026
71f7299
Replace Function roundToNearest15() with roundToNearest15Min()
johnnyq Jul 14, 2026
746e919
Replace Function getFallBack with valueOrDash()
johnnyq Jul 14, 2026
2181e92
Removed valueOrDash Function was able to replace with ?: '-'
johnnyq Jul 14, 2026
ee7ef71
Correct plugins to libs path for zapCal library in functions
johnnyq Jul 14, 2026
eac913e
Remove function removeEmoji() as this is no longer needed as the DB C…
johnnyq Jul 14, 2026
cddcedb
Cleanup format Functions
johnnyq Jul 14, 2026
bcb244c
Update skipped function renames in anything named vendor
johnnyq Jul 14, 2026
c3a438e
Replace the rest of the getFallBack Functions with simple ?: '-'
johnnyq Jul 14, 2026
38a042d
Remove _details and use singular filename for certain objects
johnnyq Jul 15, 2026
dae7f09
Remove _details, fix plural and singular file naming in admin, update…
johnnyq Jul 15, 2026
dfedc31
Update Tax to Tax Rates in admin side nav
johnnyq Jul 15, 2026
6e20800
Update Tax to Tax Rate in headr title for tax rates
johnnyq Jul 15, 2026
6dbe84d
Update admin/ breadcrumbs to match plural file names
johnnyq Jul 15, 2026
df3a24e
Feature: Secure File Download Handler Implemented
johnnyq Jul 15, 2026
33a2929
Feature: Secure File Download Handler for ticket attachments Implemented
johnnyq Jul 15, 2026
c8f616e
Ticket UI: Migrated ticket Attachments to a small table class
johnnyq Jul 15, 2026
3838d05
Add secure file handler for client ticket attachment and file view al…
johnnyq Jul 15, 2026
e48ea57
Clean up agent post handler
johnnyq Jul 15, 2026
60bae12
Clean up admin post handler to match agent
johnnyq Jul 15, 2026
590bad3
Global Search: use secure file handler on files in global search
johnnyq Jul 15, 2026
89cb907
UI: Add Monospace font to timestamps in notifications listing
johnnyq Jul 15, 2026
b1c57fc
Feature: Add new js function to retrieve and Audit log Password revea…
johnnyq Jul 16, 2026
7c9bd77
Remove unused credential view model, add enforceClient Check on expor…
johnnyq Jul 16, 2026
2076bb2
Added Audit Log on Edit Credential Modal as password can be viewed here
johnnyq Jul 16, 2026
86b0e11
Enforce ClientAccess in asset modal
johnnyq Jul 16, 2026
e39ecb7
Remove Legacy OTP code and fix guest view credential
johnnyq Jul 16, 2026
906f584
Fix guest view credential totp
johnnyq Jul 16, 2026
9f11af0
Update Contributing
johnnyq Jul 16, 2026
a8ad167
Update Contributing
johnnyq Jul 16, 2026
9e84ce4
Ticket Merge: EnforceClientAccess on modal and ticket list
johnnyq Jul 16, 2026
2c09ce0
More Client Enforcement in modals across the app
johnnyq Jul 16, 2026
1251944
More Client Enforcement in modals across the app
johnnyq Jul 16, 2026
41d0299
More Client Scoping fixes
johnnyq Jul 16, 2026
e11d8f3
Harden checkFileUpload: drop content hashing for random storage names
johnnyq Jul 16, 2026
e40926c
Restore native DNS/RDAP domain lookups (lost in functions.php split)
johnnyq Jul 16, 2026
113d622
Add back missing function call
johnnyq Jul 16, 2026
9cc7e5f
Move Guest Function formatBytes to root shared functions and use in f…
johnnyq Jul 17, 2026
1a3d7a1
Bump ImapEngine from 1.25.1 to 1.25.2
johnnyq Jul 18, 2026
ce0a62b
Add Expiring Asset Warranties and Liceneses to the Dashboard
johnnyq Jul 20, 2026
a35ef02
Add Expiring in Filter Field to assets, licenses, domains and certifi…
johnnyq Jul 20, 2026
e134c89
Add Bulk and Single Refresh Domain Actions
johnnyq Jul 20, 2026
d173357
Add Bulk and Single Refresh certificate Actions
johnnyq Jul 20, 2026
058e31c
Fix Truncated Client name in side nav needs to be truncated before es…
johnnyq Jul 20, 2026
97ab1df
Feature: Add Transactions, reorg Main side nav
johnnyq Jul 21, 2026
4bb497e
Reorganize Client Side nav and the renamed Client overview to All Cli…
johnnyq Jul 21, 2026
d5a1305
Reorg Admin Side nav menu
johnnyq Jul 21, 2026
54e2005
Icon change for Mail Queue
johnnyq Jul 21, 2026
66b38b7
Get Expense from Stripe instead of Static Entry
johnnyq Jul 22, 2026
f4b1b65
Move Expense block for Stripe after intent
johnnyq Jul 22, 2026
08334b2
Add Stripe fee reconciliation to cron
johnnyq Jul 22, 2026
8ee7805
Cleanup Expense Code in post blocks and remove single use function si…
johnnyq Jul 22, 2026
5402578
Remove Static payment processing fees from database and update field …
johnnyq Jul 22, 2026
fad62ca
Remove custom_hosting tables
johnnyq Jul 22, 2026
17e4c61
Spelling Fix
johnnyq Jul 22, 2026
2b756f6
Split DB Updates into seperate files, with the cutoff being 2.0.0
johnnyq Jul 22, 2026
7ccdc94
Bump imapEngine from v1.25.2 to v1.25.3
johnnyq Jul 23, 2026
8f43b92
Use stripe_init include to init stripe and updated code everywhere
johnnyq Jul 23, 2026
5f26d75
Update Functions in ticket_edit_vendor and document link vendor and d…
johnnyq Jul 23, 2026
b853c24
Remove a few more unused vendor contact modals and update the escapin…
johnnyq Jul 23, 2026
40be809
Fix vendor modal link in service details
johnnyq Jul 23, 2026
90bc8ed
Fix broken links to modals and remove _details from service
johnnyq Jul 23, 2026
3d94846
Fix broken link to service modal in services
johnnyq Jul 23, 2026
9c65644
Update the rest of the PHP functions to use camelCase
johnnyq Jul 23, 2026
41b118a
Add formatAddress function and replace all addresses with it
johnnyq Jul 23, 2026
5846119
remove duplicate formatAddress
johnnyq Jul 23, 2026
c7b34fe
Remove leftover getFallBack in client pdf export in favor of ?: '-'
johnnyq Jul 23, 2026
e7698f1
Make better use of formatAddress function for clients listing
johnnyq Jul 24, 2026
91a1676
Update missing CSRF endpoint checks
johnnyq Jul 24, 2026
dd358da
Update missing CSRF endpoint checks missed update_db
johnnyq Jul 24, 2026
af51c43
Updated validateCSRFToken to automatically grab and compare get or po…
johnnyq Jul 24, 2026
8afc5ae
Typo fix
johnnyq Jul 24, 2026
3549c2e
Harden CSRF handling and session cookies
johnnyq Jul 24, 2026
565aff3
Set SameSite=Lax on the session cookie
johnnyq Jul 24, 2026
28f1a96
Remove dead code
johnnyq Jul 24, 2026
5c4805b
Neutralize CSV formula injection in generated exports using the new c…
johnnyq Jul 24, 2026
8813b2c
Use imapEngine lib for testing imap connection
johnnyq Jul 24, 2026
8993bce
Force No Indexes of empty directories even if enabled using .htaccess…
johnnyq Jul 25, 2026
3524010
Add enforceClientAccess to 4 bulk modals initially missing
johnnyq Jul 25, 2026
113ef4b
Add more enforceClientAccess
johnnyq Jul 25, 2026
7a793cb
Add more enforceClientAccess to agent ajax gets
johnnyq Jul 25, 2026
761b2a7
Module permissions modal enforcement sweep to match its post counterpart
johnnyq Jul 25, 2026
ff4b69b
Client Enforcement via function on client edit instad of in sql query
johnnyq Jul 25, 2026
3756561
Feature: Add Deny Client Access to Client Access Permssions - BREAKS …
johnnyq Jul 25, 2026
8d46e2a
Fix Client Permission overides to include deny allow list in projects…
johnnyq Jul 25, 2026
c509b7f
Add user-based RBAC for API keys
johnnyq Jul 25, 2026
e6daf00
Fix some broken API calls after RBAC update
johnnyq Jul 25, 2026
04bf3c2
Read API credential decrypt password from body instead of query string
johnnyq Jul 25, 2026
8870633
Prevent client portal contacts from editing their own contact record
johnnyq Jul 25, 2026
497ea3b
Centralize client portal access checks through contactCan()
johnnyq Jul 25, 2026
a26ac2c
Fixed adding saved credit cards in stipe due to API change
johnnyq Jul 25, 2026
cd34236
Fix saved-payment setup Checkout: embedded_page ui_mode + attach exis…
johnnyq Jul 25, 2026
276e84a
Expenses: Set Current Date in new expense
johnnyq Jul 26, 2026
04014da
Combined Payments and Revenues as one View called income keeps all in…
johnnyq Jul 26, 2026
32be252
Remove patch file
johnnyq Jul 26, 2026
5fc2f93
Allow negative numbers in add expense
johnnyq Jul 26, 2026
53842a5
Add URI Tabs to mail settings keeps the tab active upon saving
johnnyq Jul 26, 2026
815802f
Gate Admin UI Modals to Admin
johnnyq Jul 27, 2026
65de8c3
Prevent duplicate Stripe payment bookings and overlapping cron runs
johnnyq Jul 27, 2026
cff416d
Remove Patch
johnnyq Jul 27, 2026
409d769
Scope the cron lock per install so instances don't block each other
johnnyq Jul 27, 2026
775e8f5
Fix Cents Calc
johnnyq Jul 27, 2026
686fca9
Fix Possible duplicate emails in a race condition in mail queue
johnnyq Jul 27, 2026
a844d7b
Adds a shared flock guard used by all five cron entry points, keyed per
johnnyq Jul 27, 2026
97490be
Security Fix in recurring invoices in cron
johnnyq Jul 27, 2026
a4fdced
Rate limit 2FA code attempts and narrow the TOTP acceptance window
johnnyq Jul 27, 2026
8825661
Dump new DB Structure
johnnyq Jul 27, 2026
b18544c
Give the vault session key full entropy and guard empty-key credentia…
johnnyq Jul 28, 2026
8dcb45f
Remove Patch
johnnyq Jul 28, 2026
50352fb
Revert vault session key entropy change
johnnyq Jul 28, 2026
8295272
Fix broken ajax
johnnyq Jul 28, 2026
b555a30
Give the vault session key full entropy and guard empty-key credentia…
johnnyq Jul 28, 2026
70d165e
Claim shared item views atomically and log guest audit IPs
johnnyq Jul 28, 2026
f129311
Remove patch and update gitignore
johnnyq Jul 28, 2026
22e9358
Fix share link view accounting and quote response handling
johnnyq Jul 28, 2026
c64c76c
Rotate session ID on login and fix client portal Entra SSO
johnnyq Jul 28, 2026
4c65b8c
Clear mail bodies after successful delivery
johnnyq Jul 28, 2026
2e855f6
Require credential module access to view or share credentials
johnnyq Jul 28, 2026
7327ebb
Stop parallel login attempts from bypassing the rate limits
johnnyq Jul 28, 2026
c3896ba
Add Export CSV to the new combined income page
johnnyq Jul 28, 2026
5f3a0be
Remove old payments and revenues and all ties to the pages as these a…
johnnyq Jul 28, 2026
7f7880a
Add Quick Payments view modal in Invoices
johnnyq Jul 28, 2026
c5ff3e2
Normalize line endings to LF; add .gitattributes and .editorconfig
johnnyq Jul 28, 2026
78e7e1c
Remove Normalize Scripts
johnnyq Jul 28, 2026
556ab22
Enfoce Sales Permission Read on products export
johnnyq Jul 28, 2026
0031438
Update Contrubuting
johnnyq Jul 28, 2026
b3f959a
Use Short echo tags across the code
johnnyq Jul 28, 2026
31921ee
Add Refunding capability along with Stripe Refunding
johnnyq Jul 29, 2026
1494d2c
Backed out of Refunds which still keeps the fix to properly set the i…
johnnyq Jul 29, 2026
78ee38b
Revert DB Update
johnnyq Jul 29, 2026
d08ef61
Add optional ticket SLAs
johnnyq Jul 29, 2026
dd45a0f
Update DB Structure
johnnyq Jul 29, 2026
d5ed050
Allow selecting client SLA assignments on client create/edit
johnnyq Jul 29, 2026
07c73a6
Add Urgent Priority, move Per Client SLA Settings to notes tab in cli…
johnnyq Jul 29, 2026
e76b384
Add ticket reply API endpoints
johnnyq Jul 29, 2026
162a597
Add SLA pausing, SLA reports, SLA filtering and kanban SLA state (pha…
johnnyq Jul 29, 2026
cc651c1
DB Structure Update
johnnyq Jul 29, 2026
9533da4
Repair SLA verdicts missed by kanban/portal resolve; record first res…
johnnyq Jul 29, 2026
750c2e5
Update DB Structure
johnnyq Jul 29, 2026
566d74c
Fix SLA resolve-time reporting, stale settings cache on save, and rep…
johnnyq Jul 29, 2026
bb1f0d5
SLA Fixes
johnnyq Jul 29, 2026
fc5cdee
Add UI Elements for Asset Notes similar to contact notes
johnnyq Jul 29, 2026
a900b2c
Update DB Structure
johnnyq Jul 29, 2026
af9990f
Fix Contact Notes and Fix a few broken links
johnnyq Jul 29, 2026
9c123c4
Update Changelog
johnnyq Jul 29, 2026
bc64c9e
Feature: Abiliry to assign Ticket Templates to Recurring Tickets
johnnyq Jul 29, 2026
7245ff0
Fix Cron URL Key on recurring tickets
johnnyq Jul 29, 2026
75d8b4d
Fix get FieldByID spots
johnnyq Jul 29, 2026
eaf3f5a
Add Badge next to recurring tickets with a template
johnnyq Jul 29, 2026
3296e48
Unlink template from recurring ticket if template is deleted
johnnyq Jul 29, 2026
8a09285
Fixed Asset section in recurring ticket if global added project in ad…
johnnyq Jul 29, 2026
d010249
Retire v1 Ticket and merge into 1 add ticket
johnnyq Jul 29, 2026
74a5359
Move Watchers into assignment in add ticket
johnnyq Jul 29, 2026
e74307e
Feature: Add Dynamic Task editing in add ticket and add recurring tic…
johnnyq Jul 29, 2026
7c8c93c
Feature allow agents to attach files to tickets in the app
johnnyq Jul 29, 2026
2395a3e
Phase 2 of ticket attachements by agents
johnnyq Jul 29, 2026
729d22d
Move Attachments to Assignment in new ticket get rid of help texts in…
johnnyq Jul 29, 2026
3c8f812
Feature: On all export modals added Filter Tab and Selectable Columns…
johnnyq Jul 30, 2026
f2d5ac4
Feature: Calendars are now exportable shareable so Third Party Calend…
johnnyq Jul 30, 2026
1005b73
DB Structure Update
johnnyq Jul 30, 2026
38e8ede
Cron runs all jobs from a single dispatcher cron.php which should now…
johnnyq Jul 30, 2026
119334a
Cron Fix
johnnyq Jul 30, 2026
0631c45
Fix Cron Schedule and new directory includes created inside cron for …
johnnyq Jul 30, 2026
36c9c03
DB Update
johnnyq Jul 30, 2026
8436cd6
Nightly tasks: apply late fees, overdue reminder emails, and autopay …
johnnyq Jul 30, 2026
09a74d6
Update changelog and Important Upgrade Steps
johnnyq Jul 30, 2026
7c55796
Cron: daily jobs catch up when the dispatcher is invoked before their…
johnnyq Jul 30, 2026
293ba53
Simplified Changelog
johnnyq Jul 30, 2026
16000ef
Drop SVG extension in the ticket mail parser
johnnyq Jul 31, 2026
6a5cf67
Add Indexes to foreign key in ticket replies and attachments fixes sl…
johnnyq Jul 31, 2026
ae468d6
Encrypted backups with types, scheduling and CLI restore
johnnyq Jul 31, 2026
53f45fa
Fix queued backups never building, per-type retention, and cron conne…
johnnyq Jul 31, 2026
abe02d7
Fix Wording on changelog
johnnyq Jul 31, 2026
4fec577
Recurring Expense: Fix edit not keeping client
johnnyq Aug 1, 2026
cdb4a43
Major UI/UX overhaul on Tickets listing / Kanban and ticket details
johnnyq Aug 1, 2026
75028ba
Fix some Ticket History gaps
johnnyq Aug 1, 2026
23a09f5
Reworked getFieldById to remove escaping and and reworked everything …
johnnyq Aug 1, 2026
6107d9f
Update Contributing
johnnyq Aug 1, 2026
056db26
Rever old test run of using prepared mysql statement for client add /…
johnnyq Aug 1, 2026
c8dab1a
Revert PAyment cleanInput too
johnnyq Aug 1, 2026
ab41543
Remove unused DB wrappers
johnnyq Aug 1, 2026
cf4446f
Bump imapengine from 1.25.3 to 1.25.4
johnnyq Aug 2, 2026
3e532fc
Update imapengine dependancies too
johnnyq Aug 2, 2026
89fba24
Add some missing maxlength form options to prevent info overflow and …
johnnyq Aug 2, 2026
e793804
Migrate credential password from varbinary to varchar and set max len…
johnnyq Aug 2, 2026
ad15fab
Credential length guard
johnnyq Aug 2, 2026
a270195
Remove unused overdue invoice setting move master cron switch out of …
johnnyq Aug 2, 2026
6b5be0f
Rework Update UI and fix banch
johnnyq Aug 2, 2026
315768d
Add Category column and filter into income along with the exports
johnnyq Aug 2, 2026
5ee1c95
Enhance .htaccess rules
Aug 3, 2026
ffe32ad
Move categories and tag types to a left side nav instead of top nav
johnnyq Aug 3, 2026
3b0d383
Merge branch 'develop' of github.com:itflow-org/itflow into develop
johnnyq Aug 3, 2026
f16e789
Bump supported version
Aug 3, 2026
ad234c5
Merge branch 'develop' of https://github.com/itflow-org/itflow into d…
Aug 3, 2026
7a44cdd
Fix Autofill products in invoice, quotes, recurring invoice, tax fiel…
johnnyq Aug 3, 2026
ea3d6a2
Merge branch 'develop' of github.com:itflow-org/itflow into develop
johnnyq Aug 3, 2026
f87d438
Add very basic product import via CSV
Aug 3, 2026
a313278
Merge branch 'develop' of https://github.com/itflow-org/itflow into d…
Aug 3, 2026
abd79c0
Feature: Add Income Bulk Actions (Account, Payment Method and category
johnnyq Aug 3, 2026
e800064
Fix Expense Description logging spelling
johnnyq Aug 3, 2026
c5288f9
Fix undefined variables in expense, asset and contact audit/flash mes…
johnnyq Aug 3, 2026
0311a3d
Fix remaing undefine vars for audits and flash messages
johnnyq Aug 3, 2026
d74c974
Feature: Add invoice_items API endpoint (adding line items to an invo…
Aug 3, 2026
8aaf5b4
Merge branch 'develop' of https://github.com/itflow-org/itflow into d…
Aug 3, 2026
c30c126
Sync DB Seed data between setup and setup cli
johnnyq Aug 4, 2026
5eba64a
Bump TinyMCE to 8.8.2
johnnyq Aug 4, 2026
1b38656
Bump DataTables from 2.3.7 to 3.0.1
johnnyq Aug 4, 2026
261bdab
Gate SLA option in ticket details its gated everywhere else
johnnyq Aug 4, 2026
f9ae759
Bump FullCalendar from 7.0.0 to 7.0.2
johnnyq Aug 4, 2026
b39f3c0
Redesing task bar and remove redundant task count in ticket details
johnnyq Aug 4, 2026
cbf8922
Update Changelog
johnnyq Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Editor defaults for ITFlow - see CONTRIBUTING.md ("Style")
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.md]
trim_trailing_whitespace = false

# Vendored - do not reformat
[libs/**]
indent_style = unset
indent_size = unset
trim_trailing_whitespace = false
insert_final_newline = false
44 changes: 44 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ITFlow line-ending policy
#
# Everything ITFlow ships is LF in the repository and LF in the working tree.
# Contributors on Windows get LF too - this is deliberate. ITFlow is deployed
# to Linux/Apache and edited over sftp/ssh as often as it is cloned, so a
# checkout must be byte-identical everywhere.

* text=auto eol=lf

# Explicit for the file types we author, so nothing depends on git's guess.
*.php text eol=lf
*.js text eol=lf
*.css text eol=lf
*.html text eol=lf
*.sql text eol=lf
*.md text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.xsd text eol=lf
*.svg text eol=lf
*.txt text eol=lf
*.ini text eol=lf
.htaccess text eol=lf

# Binary assets: never touched, never diffed as text.
*.png binary
*.gif binary
*.jpg binary
*.jpeg binary
*.webp binary
*.ico binary
*.icc binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
*.crt binary
*.ser binary
*.z binary

# Vendored third-party code is preserved byte-for-byte as shipped upstream.
# Per CONTRIBUTING.md libs/ is never edited in place - it is replaced wholesale -
# so normalizing it here would create spurious diffs on the next library update.
libs/** -text
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ uploads/users/*
!uploads/users/index.php
uploads/tmp/*
!uploads/tmp/index.php
!uploads/tmp/.htaccess
uploads/backups/*
!uploads/backups/index.php
!uploads/backups/.htaccess
uploads/tickets/*
!uploads/tickets/index.php
uploads/ticket_templates/*
Expand Down Expand Up @@ -49,3 +53,5 @@ setup/custom/*
api/v1/custom/*
!api/v1/custom/readme.php
.zed

*.patch
2 changes: 1 addition & 1 deletion .htaccess
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Prevent access to .git, .github, and config.php
RedirectMatch 404 ^/(\.git|\.github|config\.php)
RedirectMatch 401 ^/(\.git|\.github|config\.php)
160 changes: 160 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

251 changes: 251 additions & 0 deletions CONTRIBUTING.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ We operate a rolling release model. Any bug fixes will be released into latest v

| Version | Supported |
|---------| ------------------ |
| 25.12 | :white_check_mark: |
| 26.08 | :white_check_mark: |

## Reporting a Vulnerability via GitHub Security Advisories

Expand Down
26 changes: 13 additions & 13 deletions admin/ai_model.php → admin/ai_models.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<a href="/admin">Admin</a>
</li>
<li class="breadcrumb-item">
<a href="ai_provider.php">AI Providers</a>
<a href="ai_providers.php">AI Providers</a>
</li>
<li class="breadcrumb-item active">AI Models</li>
</ol>
Expand All @@ -35,17 +35,17 @@
<thead class="text-dark <?php if ($num_rows == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_model_name&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_model_name&order=<?= $disp ?>">
Model <?php if ($sort == 'ai_model_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_provider_name&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_provider_name&order=<?= $disp ?>">
Provider <?php if ($sort == 'ai_provider_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_model_use_case&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_model_use_case&order=<?= $disp ?>">
Use Case<?php if ($sort == 'ai_model_use_case') { echo $order_icon; } ?>
</a>
</th>
Expand All @@ -60,23 +60,23 @@

while ($row = mysqli_fetch_assoc($sql)) {
$provider_id = intval($row['ai_provider_id']);
$provider_name = nullable_htmlentities($row['ai_provider_name']);
$provider_name = escapeHtml($row['ai_provider_name']);
$model_id = intval($row['ai_model_id']);
$model_name = nullable_htmlentities($row['ai_model_name']);
$use_case = nullable_htmlentities($row['ai_model_use_case']);
$prompt = nl2br(nullable_htmlentities($row['ai_model_prompt']));
$model_name = escapeHtml($row['ai_model_name']);
$use_case = escapeHtml($row['ai_model_use_case']);
$prompt = nl2br(escapeHtml($row['ai_model_prompt']));

?>
<tr>
<td>
<a class="text-dark text-bold ajax-modal" href="#"
data-modal-url="modals/ai/ai_model_edit.php?id=<?= $model_id ?>">
<?php echo $model_name; ?>
<?= $model_name ?>
</a>
</td>
<td><?php echo $provider_name; ?></td>
<td><?php echo $use_case; ?></td>
<td><?php echo $prompt; ?></td>
<td><?= $provider_name ?></td>
<td><?= $use_case ?></td>
<td><?= $prompt ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
Expand All @@ -88,7 +88,7 @@
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_ai_model=<?php echo $model_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_ai_model=<?= $model_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
Expand Down
22 changes: 11 additions & 11 deletions admin/ai_provider.php → admin/ai_providers.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
<thead class="text-dark <?php if ($num_rows == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_provider_name&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_provider_name&order=<?= $disp ?>">
Provider <?php if ($sort == 'ai_provider_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_provider_api_url&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_provider_api_url&order=<?= $disp ?>">
URL <?php if ($sort == 'ai_provider_api_url') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ai_provider_api_key&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=ai_provider_api_key&order=<?= $disp ?>">
Key <?php if ($sort == 'ai_provider_api_key') { echo $order_icon; } ?>
</a>
</th>
Expand All @@ -50,9 +50,9 @@

while ($row = mysqli_fetch_assoc($sql)) {
$provider_id = intval($row['ai_provider_id']);
$provider_name = nullable_htmlentities($row['ai_provider_name']);
$url = nullable_htmlentities($row['ai_provider_api_url']);
$key = nullable_htmlentities($row['ai_provider_api_key']);
$provider_name = escapeHtml($row['ai_provider_name']);
$url = escapeHtml($row['ai_provider_api_url']);
$key = escapeHtml($row['ai_provider_api_key']);

$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ai_model_id') AS ai_model_count FROM ai_models WHERE ai_model_ai_provider_id = $provider_id"));
$ai_model_count = intval($row['ai_model_count']);
Expand All @@ -62,13 +62,13 @@
<td>
<a class="text-dark text-bold ajax-modal" href="#"
data-modal-url="modals/ai/ai_provider_edit.php?id=<?= $provider_id ?>">
<?php echo $provider_name; ?>
<?= $provider_name ?>
</a>
</td>
<td><?php echo $url; ?></td>
<td><?php echo $key; ?></td>
<td><?= $url ?></td>
<td><?= $key ?></td>
<td class="text-center">
<a class="badge badge-dark badge-pill p-2" href="ai_model.php"><?= $ai_model_count ?></a>
<a class="badge badge-dark badge-pill p-2" href="ai_models.php"><?= $ai_model_count ?></a>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
Expand All @@ -80,7 +80,7 @@
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_ai_provider=<?php echo $provider_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_ai_provider=<?= $provider_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
Expand Down
51 changes: 25 additions & 26 deletions admin/api_keys.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM api_keys
LEFT JOIN clients on api_keys.api_key_client_id = clients.client_id
LEFT JOIN users on api_key_user_id = user_id
WHERE (api_key_name LIKE '%$q%')
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
Expand All @@ -33,7 +33,7 @@

<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search keys">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(escapeHtml($q)); } ?>" placeholder="Search keys">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
Expand Down Expand Up @@ -64,7 +64,7 @@
<div class="table-responsive-sm">

<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">

<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
Expand All @@ -75,27 +75,27 @@
</div>
</td>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_name&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=api_key_name&order=<?= $disp ?>">
Name <?php if ($sort == 'api_key_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_client_id&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'api_key_client_id') { echo $order_icon; } ?>
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=api_key_user_id&order=<?= $disp ?>">
User <?php if ($sort == 'api_key_user_id') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_secret&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=api_key_secret&order=<?= $disp ?>">
Secret <?php if ($sort == 'api_key_secret') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_created_at&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=api_key_created_at&order=<?= $disp ?>">
Created <?php if ($sort == 'api_key_created_at') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_expire&order=<?php echo $disp; ?>">
<a class="text-dark" href="?<?= $url_query_strings_sort ?>&sort=api_key_expire&order=<?= $disp ?>">
Expires <?php if ($sort == 'api_key_expire') { echo $order_icon; } ?>
</a>
</th>
Expand All @@ -107,45 +107,44 @@

while ($row = mysqli_fetch_assoc($sql)) {
$api_key_id = intval($row['api_key_id']);
$api_key_name = nullable_htmlentities($row['api_key_name']);
$api_key_secret = nullable_htmlentities("************" . substr($row['api_key_secret'], -4));
$api_key_created_at = nullable_htmlentities($row['api_key_created_at']);
$api_key_expire = nullable_htmlentities($row['api_key_expire']);
$api_key_name = escapeHtml($row['api_key_name']);
$api_key_secret = escapeHtml("************" . substr($row['api_key_secret'], -4));
$api_key_created_at = escapeHtml($row['api_key_created_at']);
$api_key_expire = escapeHtml($row['api_key_expire']);
if ($api_key_expire < date("Y-m-d H:i:s")) {
$api_key_expire = $api_key_expire . " (Expired)";
}

if ($row['api_key_client_id'] == 0) {
$api_key_client = "<i>All Clients</i>";
} else {
$api_key_client = nullable_htmlentities($row['client_name']);
}
$api_key_user = !empty($row['user_name']) ? escapeHtml($row['user_name']) : "<i>None</i>";

?>
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="api_key_ids[]" value="<?php echo $api_key_id ?>">
<input class="form-check-input bulk-select" type="checkbox" name="api_key_ids[]" value="<?= $api_key_id ?>">
</div>
</td>
<td class="text-bold"><?php echo $api_key_name; ?></td>
<td><?php echo $api_key_client; ?></td>
<td><?php echo $api_key_secret; ?></td>
<td><?php echo $api_key_created_at; ?></td>
<td><?php echo $api_key_expire; ?></td>
<td class="text-bold"><?= $api_key_name ?></td>
<td><?= $api_key_user ?></td>
<td><?= $api_key_secret ?></td>
<td><?= $api_key_created_at ?></td>
<td><?= $api_key_expire ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/api/api_key_edit.php?id=<?= $api_key_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if ($api_key_expire > date("Y-m-d H:i:s")) { ?>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?revoke_api_key=<?php echo $api_key_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?revoke_api_key=<?= $api_key_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-times mr-2"></i>Revoke
</a>
<?php } ?>
<?php if ($api_key_expire < date("Y-m-d H:i:s")) { ?>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_api_key=<?php echo $api_key_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_api_key=<?= $api_key_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-times mr-2"></i>Delete
</a>
<?php } ?>
Expand Down
Loading
Loading