fix: comprehensive bug fixes, hardening, and test coverage
Bug fixes: - Fix nil-pointer panic in sendMessage SOAP fault handler (used err.Error() on nil) - Fix missing return after SOAP fault response (caused fall-through to 200 OK) - Fix timeout=0 shadowing: removed package-level constant, use configured value - Fix receiveMessage not checking SOAP faults from CIIMS Codec hardening: - Replace fragile regex parsing with encoding/xml.Decoder for namespace-agnostic XML - XML-escape all user inputs (user, pass, event) — not just message body - Remove magic-number-based string slicing (split, GetErrMsg) Transport improvements: - Extract Client type with connection pooling (reuse http.Client across requests) - Add CIIMSResponse domain type with IsFault(), ErrorMessage(), Messages() - Add HTTPStatusError and ResponseTooLargeError typed errors - Replace deprecated ioutil.ReadAll with io.ReadAll - Add response body size limit (64 MiB) Security hardening: - Add MaxBytesReader (1MB request body limit) on both endpoints - Add URL allowlist via CIIMS_ALLOWED_SERVERS env var - Add normalizeBaseURL with scheme/host/query validation - Add count bounds validation (1-1000) on /receive - Add server-level timeouts (ReadHeaderTimeout, ReadTimeout, IdleTimeout) Configuration: - Introduce Config struct to replace package-level globals - Add loadConfig() with full validation and error propagation - Add getIntEnv() with positive-value enforcement Test coverage (75 tests, 35 new): - Phase 1: 8 internal tests (nil receiver, error types, SOAP+HTTP500, malformed XML) - Phase 2: 19 pure function tests (normalizeBaseURL, parseAllowedServers, getIntEnv) - Phase 3: 16 handler tests (send/receive success, SOAP fault, network error, HTTP 500, body too large, invalid JSON, missing fields, URL allowlist) - Phase 4: 8 config/router tests (loadConfig, newServer, newRouter) Toolchain: - Upgrade Go 1.13 → 1.22, gin 1.6.3 → 1.10.0, testify 1.5.1 → 1.10.0 Cleanup: - Remove dead code (unused post() function, commented-out defaults) - Replace println with structured logging - Add .gitignore - Rewrite README with API docs, env vars, security considerations
This commit is contained in:
@@ -1,31 +1,85 @@
|
||||
# CIIMS web service message exchange proxy
|
||||
|
||||
A thin HTTP proxy that translates JSON POST requests into SOAP/XML calls to a CIIMS
|
||||
ExchangeService backend. Designed for airport operational message exchange (AODB/FLOP).
|
||||
|
||||
## send
|
||||
## API
|
||||
|
||||
* context: /send
|
||||
### POST /send
|
||||
|
||||
Send a message to CIIMS.
|
||||
|
||||
Request body (JSON):
|
||||
```json
|
||||
{
|
||||
"url":"http://domain.tld",
|
||||
"user":"ciims username",
|
||||
"pass":"ciims password",
|
||||
"event":"route event id",
|
||||
"priority":0,
|
||||
"val": false,
|
||||
"msg":"ciims xml message body"
|
||||
"url": "http://domain.tld", // optional, overrides CIIMS_SERVER
|
||||
"user": "ciims username", // required
|
||||
"pass": "ciims password", // required
|
||||
"event": "route event id", // required
|
||||
"priority": 0, // optional, defaults to 0
|
||||
"val": false, // optional, defaults to false
|
||||
"msg": "ciims xml body" // required
|
||||
}
|
||||
```
|
||||
### url, priority, val is optional
|
||||
|
||||
## receive
|
||||
### POST /receive
|
||||
|
||||
* context: /
|
||||
Receive messages from CIIMS.
|
||||
|
||||
Request body (JSON):
|
||||
```json
|
||||
{
|
||||
"url":"http://domain.tld",
|
||||
"user":"ciims username",
|
||||
"pass":"ciims password",
|
||||
"count": 3
|
||||
"url": "http://domain.tld", // optional, overrides CIIMS_SERVER
|
||||
"user": "ciims username", // required
|
||||
"pass": "ciims password", // required
|
||||
"count": 3 // required, 1-1000
|
||||
}
|
||||
```
|
||||
### url is optional
|
||||
|
||||
### GET /ping
|
||||
|
||||
Health check — returns `{"message": "pong"}`.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Environment Variable | Description | Default |
|
||||
|---|---|---|
|
||||
| `CIIMS_SERVER` | Base URL of the default CIIMS ExchangeService | (required) |
|
||||
| `CIIMS_ALLOWED_SERVERS` | Comma-separated extra CIIMS base URLs allowed for request `url` overrides | empty |
|
||||
| `PROXY_LISTEN` | Bind address for the proxy HTTP server | `:9090` |
|
||||
| `CIIMS_TIMEOUT` | Outbound request timeout in seconds | `240` |
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Authentication:** This proxy does not authenticate callers. Deploy behind a firewall or
|
||||
add a reverse-proxy layer (nginx, envoy) with API key / basic auth.
|
||||
- **TLS:** Use a TLS-terminating reverse proxy in production. The proxy itself serves plain
|
||||
HTTP and transmits CIIMS credentials with every request.
|
||||
- **Input limits:** Request bodies are limited to 1 MB, CIIMS responses are limited to 64 MiB, and the `count` parameter on `/receive`
|
||||
is capped at 1000.
|
||||
- **URL overrides:** Per-request `url` values are accepted only when they match `CIIMS_SERVER` or an entry in `CIIMS_ALLOWED_SERVERS` after normalization.
|
||||
- **Credentials:** CIIMS usernames and passwords are XML-escaped before being embedded in
|
||||
SOAP envelopes. They are not logged.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
go build -o ciimsproxy ./cmd/main/
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
# Start the proxy
|
||||
CIIMS_SERVER=http://192.168.1.100:8080 ./ciimsproxy
|
||||
|
||||
# Send a message
|
||||
curl -X POST http://localhost:9090/send \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"user":"FIMS","pass":"FIMS","event":"FLOP-CHDT","msg":"<MSG/>"}'
|
||||
|
||||
# Receive messages
|
||||
curl -X POST http://localhost:9090/receive \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"user":"FIMS","pass":"FIMS","count":5}'
|
||||
```
|
||||
Reference in New Issue
Block a user