Ownware
Home›Confida›Manual
Confida · Manual

Confida Manual, as shipped in the download

Confida — User Manual

A confidential reporting channel you host yourself. Version 3.1.6 [src: app/controllers/api.php:26].

About this manual

Every statement here was written by reading Confida's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.

Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out — which matters more here than in most products, because somebody may rely on it.

What Confida is

A reporting channel with two sides. Somebody submits a report without an account [src: app/index.php:70]; a handler works it; and the two can exchange messages without the reporter ever identifying themselves [src: app/index.php:77].

Making a report

A report's description and each message in the thread are accepted up to 100,000 characters; longer text is refused with a message rather than lost [src: app/src/Report.php:65].

The reporting form is public and needs no sign-in [src: app/index.php:70]. On submission the reporter is given a case code and sets a passphrase.

The case record stores no IP address. The table holds the code, the passphrase hash, a category, subject, details, status, the clocks and the timestamps — and nothing that identifies the machine the report came from [src: app/src/Database.php:206]. The one place the application looks at a caller's address is rate-limiting for staff logins [src: app/controllers/app.php:14].

Coming back to a report

A reporter returns through the tracking page with their code and passphrase [src: app/index.php:75].

The code is generated from an alphabet without look-alike characters and checked for uniqueness, throwing rather than issuing a duplicate [src: app/src/Report.php:158]. When it is typed back in it is normalised — upper-cased, with spaces and dashes stripped — so a code written on paper and read back with hyphens still works [src: app/src/Report.php:171].

The passphrase is hashed, not stored [src: app/src/Report.php:176], and checked by verification rather than comparison [src: app/src/Report.php:181]. The consequence is worth stating plainly: nobody can recover it, including you. A reporter who loses their passphrase loses access to that thread, and no administrator can restore it. That is the cost of the guarantee.

There is a sign-out on the tracking page which clears the session [src: app/controllers/app.php:348]. It exists for shared or borrowed computers.

Attachments

Attachments get two separate protections, and the order matters.

First, the file is stripped

An attachment is accepted only if its identifying metadata can be removed by parsing the file itself [src: app/src/Scrub.php:33].

For a JPEG, every application marker segment is removed — which is where EXIF and GPS live, along with maker notes, the embedded thumbnail, XMP and Photoshop resource blocks — and comment segments go too [src: app/src/Scrub.php:45]. For a PNG, only the critical chunks and transparency survive; the text chunks that carry author, software and comments are dropped, as are the EXIF and modification-time chunks [src: app/src/Scrub.php:77].

Anything else is refused rather than accepted. The source gives the reason: a PDF or an office document carries author metadata that cannot be reliably removed without a full parser, so the product says no instead of pretending [src: app/src/Scrub.php:3].

That refusal is the feature. A product that accepted a PDF and quietly failed to clean it would be worse than one that accepts nothing.

Then the bytes are sealed

What survives scrubbing is encrypted at rest with AES-256-GCM, under a key derived from the installation's own secret [src: app/src/Vault.php:26]. The key is derived rather than used raw, and is never logged [src: app/src/Vault.php:20].

The trade is stated in the source and you should understand it before relying on backups: losing config.php means losing the attachments [src: app/src/Vault.php:3]. That is intended. It is what makes a stolen backup tape, a copied VM snapshot or a shared-host neighbour unable to read an attachment they can otherwise reach.

Who can open one

An attachment is served to the reporter whose session owns the case, or to a handler with the case permission [src: app/controllers/app.php:328]. Where a case is sealed under the two-person rule, a handler is refused outright [src: app/controllers/app.php:331].

The two-person rule

A case can be marked so that no single handler can open it alone [src: app/controllers/v3.php:108].

Opening one takes two steps by two different people. A handler requests access; then a handler other than the one who requested it must confirm before the case's details and message history can be read or answered — and both names are recorded permanently [src: app/controllers/v3.php:114].

Until that happens the case stays sealed, and the refusal says so rather than presenting an empty page [src: app/controllers/app.php:331].

The clocks

Two deadlines run on every case.

Acknowledgement is a number of days from receipt, seven by default [src: app/src/Report.php:79].

Feedback is a number of months, three by default, anchored on the date the case was actually acknowledged where that happened, and on the acknowledgement deadline where it did not [src: app/src/Report.php:122]. A case that was never acknowledged does not get a later feedback deadline for having been ignored.

Statutory and observed dates are kept apart

This is the design decision worth understanding. The statutory dates are never adjusted. A second, observed date is computed alongside them, moving the deadline forward off a weekend or one of your own non-working days, and both are shown [src: app/src/Report.php:89].

The observed date can only ever move later, so nothing becomes overdue sooner because the feature exists [src: app/src/Report.php:91].

Your non-working days come from a holiday table you maintain [src: app/controllers/app.php:723], read into the calculation when deadlines are worked out [src: app/controllers/app.php:435]. Nothing is hardcoded: the source is explicit that the product ships no country's calendar and guesses no jurisdiction [src: app/src/Report.php:94].

Status is derived

A case's service-level status is worked out from the row and today, never stored [src: app/src/Report.php:134]. Closed and dismissed cases report as on track — the clock stops when the matter does. Otherwise a passed feedback deadline reports as feedback overdue, and an unacknowledged case past its acknowledgement deadline reports as acknowledgement overdue [src: app/src/Report.php:134].

Owners and reminders

A case can have a named owner, chosen from the active handlers and administrators; the choice is written to the case log [src: app/controllers/v3.php:369]. When reminders are switched on in Settings, the owner and the handler notification address are emailed before the acknowledgement and feedback deadlines (3 and 1 days before by default) and once on the day after either passes [src: app/controllers/v3.php:278]. Like every Confida email, a reminder carries the case code and a date, never report content. Each step is sent once; it is checked when someone opens the dashboard, and a daily cron call to reminders/run with the scheduled-backup token covers days nobody does [src: app/controllers/v3.php:354]. A reminder that could not be delivered is recorded on the case log and shown on the dashboard.

Email

Handler notifications and reminders go through your own SMTP server. The encryption is a setting: STARTTLS (587), SSL/TLS (465) or none [src: app/controllers/app.php:826].

Users, roles and what each may do

Three roles [src: app/controllers/v3.php:57].

Permissionviewermemberadmin
case.viewyesyesyes
audit.viewyesyesyes
case.handle—yesyes
case.read_thread—yesyes
views.save—yesyes
everything else——yes

Note that reading the message thread is its own permission, separate from seeing that a case exists [src: app/controllers/v3.php:57].

The API and agent access

Machine access uses a key [src: app/index.php:100]. Cases can be listed and fetched, a status set, and the service-level position pulled [src: app/index.php:101].

Four tools are exposed to an agent, of which one writes [src: app/controllers/v3.php:57]:

ToolWrites?What it does
list_casesnoCases with derived service-level status
case_detailnoOne case with its report, action log and message thread
statsnoCounts by workflow and service-level status, and what is overdue
post_handler_messageyesPosts a message to the reporter on a case

The writer always posts as the handling side rather than impersonating an individual [src: app/controllers/v3.php:57].

What Confida does not do

It does not make a reporter anonymous. It stores no IP address against a case [src: app/src/Database.php:206] and requires no account [src: app/index.php:70], which is what the application controls. It does not control your web server's access logs, your network, your reverse proxy, or the fact that a report's contents may identify its author to anyone who knows the department. Telling somebody they are anonymous because the software stores no address would be an overstatement, and this manual will not make it.

It cannot recover a lost passphrase [src: app/src/Report.php:176]. That is a guarantee, not a defect, and it should be explained to reporters when they are given a code.

It refuses attachments it cannot clean [src: app/src/Scrub.php:3]. Images it can strip are accepted; documents are not, because their metadata cannot be reliably removed.

It does not decide anything. It records reports, runs two clocks and keeps a trail. Whether a report is well-founded, and what is done about it, are yours.

← Back to Confida · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →