# Technical documentation — eitaws (eIT)

Evidence date: 2026-10-15. Source: `git@bitbucket.org:overdrive/eitaws.git`.

Secrets are named by file. Password values are not copied here.

The file-level description is `master` at `9dc596e` (2020-07-02, "API URL", Kagiso Malepe). Other branch tips are listed and were not checked out.

## Repository

| Item | Value |
|---|---|
| Origin | `git@bitbucket.org:overdrive/eitaws.git` |
| Default branch | `master` |
| Default tip | `9dc596e` — 2020-07-02 — "API URL" — Kagiso Malepe |
| `development` | `b65353c` — 2022-08-16 — "sanitise special character function fix" — Uriel Balela |
| `php8.2_upgrade` | `17740b0` — 2024-03-08 — merge of pull request #24 — Joshua G-D |
| `php8.2_upgrade---Wessels` | `a02bca9` — 2024-01-17 — Wessels |
| `php8.2_upgrade_josh` | `00fb327` — 2026-03-06 — "Add trimming" — Joshua G-D |
| README | One line: "31 Mar 2020 - Current working version on AWS" |
| License, changelog | None found |
| Tests | No project suite. `vendor/christian-riesen/base32/tests/` belongs to the library |
| CI | `bitbucket-pipelines.yml` only. No test step |

History before `9dc596e` was not fetched. The reading clone is depth 1, plus the four branch tips above.

## Stack

| Layer | What the tree shows |
|---|---|
| Language | PHP. No version constraint in `composer.json`. `phpinfo.php` and `info.php` exist |
| Database access | `mysqli` through `includes/db_connect.php` and `includes/db_sql.php`. A comment in `_nemo.database2.cls.php` (2014-11-26) says the mysqli class replaced the old `mysql` API |
| Web UI | HTML 4.01, table layout, jQuery 1.8.6 (`scripts/jquery.js`), jQuery UI 1.8.6, and jQuery 3.3.1 loaded by the invoice export page |
| Composer | `wayne-oliver/otp` `^0.0.1`, which pulls `christian-riesen/base32`. `composer.lock` is committed. `vendor/` is committed |
| PDF | FPDF, mPDF, html2pdf, htmltopdf, each vendored as a directory |
| Excel | PHPExcel and `plugins/SimpleXLSX.cls.php` |
| Mail library | `PHPMailer-master/` on disk. To-do notification uses `mail()` |
| QuickBooks | Consolibyte PHP framework under `quickbooks_webservices/QuickBooks/` |
| Front-end hash | `scripts/md5.js` on the login form |

Application code does not reference `OTP` or `TOTP`. The dependency is unused on this branch.

## Application structure

Request path for a normal signed-in page:

1. `sheet.php` turns on `display_errors` and `E_ALL`.
2. It includes `includes/db_connect.php`, `includes/db_sql.php`, `includes/system.php`, `includes/sql_object.cls.php`, and `systemfunctions.php`.
3. `includes/system.php` copies `$_GET`, `$_POST`, and `$_COOKIE` onto `$GLOBALS` (`gpc_extract`). Magic quotes are stripped when that PHP feature is on.
4. `checkLogin()` runs.
5. An entity name selects `entities/<folder>/_controller.php`, which includes an action file and then `view_list.php` or `view_details.php`.
6. `header.php` and `includes/menu.php` wrap the entity. `footer.php` is a short close.

Legacy buttons (`btnShow`, `btnShowStock`, `btnSystem`, `btnHR`, and many save buttons) skip the entity include and continue in `sheet.php`.

`includes/system.php` then narrows `error_reporting` to exclude `E_STRICT`, `E_NOTICE`, and `E_WARNING`, while leaving `display_errors` on.

### Entity folders on the menu

| Folder | Menu control |
|---|---|
| `entities/billing` | Billing List, and the default when the request is empty |
| `entities/todo` | Todo List |
| `entities/tracking` | Tracking |
| `entities/mlpa` | MLPA |
| `entities/insurance` | Insurance |
| `entities/client` | Clients |
| `entities/requests` | Requests link |
| `entities/feedback` | HR link, and the public login-page link |
| `entities/sla` | System, when the user may edit support contracts |
| `entities/user` | System → System Users |
| `entities/labourcodefault`, `entities/labourcodefix` | System, level 7 or 9 |
| `entities/clientdomains` | System, support-contract flag |
| `entities/settingsbackupassessment` | System → Client Backup Assessment Settings |

`entities/example` and `entities/contact` have controllers and are not in the top menu that was read.

## Database

The PHP application uses MySQL (or a compatible server) via mysqli. The DSN is not in git.

`.gitignore` contains one line:

```text
includes/db_connect.php
```

Tables named by the code that was read:

| Table | Used for |
|---|---|
| `tblUser` | Staff, level, flags, password |
| `sysSettings` | At least `ExternalLoginPin` |
| `tblClient` | Clients, lock, fixed support amount, transit |
| `tblContact` | People at a client |
| `tblBilling` | Support billing lines, invoice number, status |
| `tblBillingCode`, `vBillingCode` | Codes, `blnBill`, type (`SLA`, `Fixed SLA`) |
| `tblSLA` | SLA hours and rate |
| `tmpBilling` | Month-end working set. Deleted and refilled each run |
| `tblBillingContact` | Contacts on a billing line |
| `tblTracking` | Machine register |
| `tblMLPA` | MLPA register |
| `tblDeviceType`, `tblPCSupplier`, `tblPCAntivirus`, `tblPCHDT`, `tblPCMemory`, `tblPCMotherBoard`, `tblPCOffice`, `tblPCWindows` | Tracking lookups |
| `tblCodeFault` | Fault codes |
| `tblType`, `tblCategory`, `tblPaymentType` | Billing classification |
| `tblX` | Internal change requests |
| `tblConnBlackBerry`, `tblConnFTP` | Client connectivity rows named in the client screen query |

Schema notes committed as text, not as migrations:

- `DB changes.txt`: `tblClient.blnLocked`; `tblTracking.strModel`, `blnClientNotificationSent`, `blnClientQuoteRequested`, `blnClientQuoteRejected`.
- `Albert SQL statements.txt`: `tblBilling.blnSLAClosed`.

There is no `app/Database/Migrations` tree. Schema change is manual SQL.

Access files at the root (`accounts.mdb`, `adsl.mdb`, `billing_lamp.mdb`, `Database.mdb`, `db1.mdb`, `linked.mdb`, `stock.mdb`, plus backups) are not opened by the PHP includes that were read. Whether they were the source of an old import is **Unknown / Requires Confirmation**.

The Web Connector uses a second database, name `quickbook_webservice`, configured in `quickbooks_webservices/config.php`. That file contains a username and password in the DSN. Do not copy them into tickets or docs. **Requires Confirmation** that the password has been rotated, because it is in git history on `master`.

## Authentication

| Item | Behaviour |
|---|---|
| Login page | `index.php` |
| Password transport | Browser MD5, then server compares to `md5` of the stored column |
| Second field | Shared `ExternalLoginPin` |
| Session | Unsigned cookie `myCookie` |
| Level | First character: 5, 7, or 9 |
| User id | Remainder of the cookie |
| Idle refresh | Every authenticated `sheet.php` hit extends the cookie by 14370 seconds |
| OTP | Library present, no call site |
| `phpinfo` | `phpinfo.php` and `info.php` |

`gpc_extract` promotes request parameters to globals. The `overdrive=silicon` branch reads `$username` and `$password` from that mechanism.

## QuickBooks

### Online month-end

`QB_API_AUTH_URL` is `https://qb.overdrive.co.za/auth/`.

`createQBInvoice()` builds a `Line` map keyed by client name. Each line has description, quantity, billing-code name, unit price, and billing id. The browser sends that as `stream`, plus `request_url` and `app=eit`, by synchronous jQuery GET. Success opens the response. Failure alerts the jqXHR.

`sheet.php` accepts `QBAPI` after `checkLogin()` and writes invoice numbers with interpolated SQL.

The auth service is not in this repository.

### Web Connector

| File | Role |
|---|---|
| `quickbooks_webservices/qbwc.php` | SOAP endpoint |
| `qbwcEIT.php`, `qbwcTS.php` | Further endpoints. "TS" was not expanded in the files that were opened |
| `handler.php`, `handlerEIT.php`, `handlerTS.php` | Request handlers |
| `functions.php`, `functionsEIT.php`, `functionsTS.php` | qbXML invoice add, with comments pointing at the Consolibyte wiki |
| `eit.connection.php`, `quote.connection.php`, `ts.connection.php` | Connection wrappers |
| `cron.hourly.php` | Scheduled entry. The host crontab is not in the repo |
| `config.php` | Time zone `Africa/Johannesburg`, Web Connector user, MySQL DSN |
| `example_web_connector_auth.php`, `dev_qbwc_tester.php` | Examples and a tester. The tester defaults to `https://qbwc/QuickBooks/QBWebConnectorSvc.wsdl` |

`config.php` still matches the upstream Consolibyte sample structure, with local values filled in.

## Mail

`sendTodoEmail()` uses PHP `mail()` and HTML headers. The From address is the assignee. There is no queue and no retry in that function.

Other mail entry points found by name: `includes/mail_report.php`, `includes/mail_order_num_report.php`, `includes/send_general_email.php`. Their SMTP settings were not read. `_nemo.email.cls.php` is a Nemo mail class at the repo root and is not what `sendTodoEmail()` calls.

## Background work

| Entry | What was confirmed |
|---|---|
| `quickbooks_webservices/cron.hourly.php` | File exists. Schedule is outside the repo |
| `fim_2.0/fim.cron.php` | Reads `sesFile.txt`, then switches on `Action`, including "FIM: PULL MASTER DATA" |
| `fim_2.0/fim.cls.php` | Class `NemoFIM`. Sets directory permissions (checks `0755`) and walks a root with exclude wildcards from config |
| `fim_2.0/fim.config.php`, `fim.config_live.php` | Two configs. Values were not copied |

No queue server (SQS, beanstalkd, Redis worker) appears in the application includes that were searched.

## Deployment

`bitbucket-pipelines.yml`:

- Image `python:3.5.7`.
- Runs only for branch `development`.
- Installs `zip`, `git`, and `git-ftp`.
- `git ftp push` to `ftp://$FTP_HOST_LIVE` with `FTP_USERNAME_LIVE` and `FTP_PASSWORD_LIVE`.
- `git ftp init` is commented and marked for first-time use.

No Dockerfile, Serverless template, CloudFormation, or Elastic Beanstalk config was seen at the top of `master`. The README's AWS claim is therefore a note, not a deploy definition. **Unknown / Requires Confirmation** which host is live.

`htaccess.bak.100919` redirects HTTP to HTTPS. It is a `.bak` file, not a live `.htaccess`. Whether the server has a real `.htaccess` was not established; none was in the root listing.

## Security notes from the tree

These are observations, not a pentest.

- `includes/db_connect.php` is the only ignored secret. Office files, Access databases, and `quickbooks_webservices/config.php` are committed.
- `display_errors` is on.
- `phpinfo.php` and `info.php` are in the web root.
- Login cookie is predictable from a level and a user id.
- SQL in the month-end path and the `QBAPI` update concatenates request data.
- `change_requests.php` has `checkLogin()` commented out. The menu reaches requests through `sheet.php`, which does check the cookie.
- MLPA PDF code in the controller contains a PDO call with an empty DSN and user `root`.
- `gpc_extract` recreates register-globals behaviour for GET, POST, and cookies.

## Development process

- Editors in the tree: Sublime projects, Komodo (`billing.kpf`), NetBeans (`nbproject/`).
- No PHPUnit config, no `.env.example` for the app, no documented local setup beyond the gitignored connect file.
- Dated copies are kept in place rather than deleted (`*_20191210`, `*_old`, `Backup_20200129`).
- Comments are the change log. Authors named in comments that were read include Maanie, Kagiso, Jacques, Trevor, Christiaan, Rachel, Russel, and pj.

## Monitoring

No application log library, health endpoint, or metrics client was identified in the app includes. `fim_2.0` is the closest operational tool, and it checks file permissions rather than request metrics. Pipeline success is the FTP push itself.
