Added avalonia integration and remote proof of concept

This commit is contained in:
MaddoScientisto 2026-02-28 15:30:57 +01:00
commit 4a0973b681
23 changed files with 2043 additions and 6 deletions

View file

@ -0,0 +1,230 @@
# API Specification (code-backed): races, images, and authentication
## Scope and evidence
This document is reverse-engineered from:
- JSP/JS usage in the web app
- `WEB-INF/web.xml` servlet mappings
- decompiled sources in `WEB-INF/lib/*_src` (notably `AblServletSvlt`, `AcServlet`, `GaraSvlt`, `Logon4Svlt`, `Menu4Svlt`, `GetFileTnSvlt`)
The upload response schemas below are now **confirmed from code**, not inferred.
## Base URL
Examples use:
- `https://your-host`
## Authentication (how to obtain the usable token)
## Actual auth model
This app uses **server session authentication**, not JWT bearer tokens.
Login success sets session attributes:
- `loginUser_id` (Long)
- `utenteLogon` (user object)
For automation, the practical token is the **session cookie** (`JSESSIONID` and any app cookies).
## Admin login endpoint
- `POST /admin/menu/Menu4.abl`
- Servlet mapping: `com.ablia.anag.servlet.Menu4Svlt` (extends `Logon4Svlt`)
- Body (`application/x-www-form-urlencoded`):
- `login`
- `pwd`
- `cmdIU=check`
Other `cmdIU` values used:
- `cmdIU=login` (logout)
- `cmdIU=np` (password change)
- `cmdIU=checkSso` (SSO branch if enabled)
### cURL login example (capture session cookie)
```bash
curl -i -c cookies.txt -X POST "https://your-host/admin/menu/Menu4.abl" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "login=YOUR_USER&pwd=YOUR_PASSWORD&cmdIU=check"
```
Reuse cookie jar for authenticated calls:
```bash
curl -i -b cookies.txt "https://your-host/admin/pg/Gara.abl?cmd=search"
```
## Token note (Bearer/Basic)
- No `Authorization: Bearer ...` flow is present in inspected sources.
- A helper exists to parse `Authorization: Basic` (`getBasicAuthorizationHeaders`), but no race/photo endpoint uses it directly.
## Relevant endpoints
## Admin race/photo endpoints
- `POST|GET /admin/pg/Gara.abl`
- `POST|GET /admin/pg/Foto.abl`
- `POST|GET /admin/pg/TipoGara.abl`
- `POST|GET /admin/pg/LogFoto.abl`
Deployment caveat:
- some deployments expose the same admin pages under `POST|GET /admin/pg_RUS/*.abl`.
- On `https://www.regalamiunsorriso.it`, post-login dashboard links point to `/admin/pg_RUS/Gara.abl` (not `/admin/pg/Gara.abl`).
## Public/web endpoints related to photos/users
- `POST|GET /Foto2.abl`
- `POST|GET /Logon.abl` (mapped to `com.ablia.pg.servlet.Logon2Svlt`)
- `POST|GET /Users.abl`
Note: `/Login.abl` in `web.xml` is mapped to cart servlet (`CartSvlt`), not admin login.
## File serving endpoints
- `GET /foto/*``GetFileTnSvlt` (thumbnail by default)
- `GET /fotoOriginali/*``GetFileOrigSvlt` (original file flow)
## Multipart upload contract (common engine)
All race-image/file uploads go through `AblServletSvlt.manageImgFileMultipartRequest` + `AcServlet.manageMultipartRequestParameters`.
Key behavior:
- File fields explicitly recognized: `imgFile`, `nomeFile`
- UI also sends `fileName` for generic file upload; this still works (stored by original filename)
- Temporary target directory: `DOCBASE + tmp/` (`getPathTmp()`)
- Per-upload file size target: about `20000 KB` for this servlet path
## Upload race image
Endpoint:
- `POST /admin/pg/Gara.abl`
Required form fields:
- `cmd=loadImg`
- `imgFile` (binary)
- `id` (race id)
- `codImage` (slot index)
- `totImgNumber` (typically `3` in UI)
Storage details:
- Race attachment path from `Gara.getPathAttach()` is `_img/_gara/`
- Thumbnail is generated into `_img/_gara/100/` (100x75)
### Response schema (confirmed)
Response is JSON array with one object (`JsonUploadImageResponse`):
- `result` (boolean)
- `message` (string)
- `imgPath` (string)
Example success payload shape:
```json
[
{
"result": true,
"message": "...Immagine 1 Salvata...",
"imgPath": "../../_img/_gara/100/<generated-file>"
}
]
```
## Delete race image
Endpoint:
- `POST /admin/pg/Gara.abl`
Fields:
- `cmd=removeImg`
- `id`
- `codImage`
- `totImgNumber`
Response schema is the same `JsonUploadImageResponse[]`.
## Upload CSV/file for race processing
Endpoint:
- `POST /admin/pg/Gara.abl`
UI helper (`Ab.saveFile`) sends:
- `cmd=saveFile`
- `fileName` (binary file)
- `codFile` (slot id, usually `1`)
- `id` (often `0` in UI flow)
### Response schema (confirmed)
JSON array with one `JsonUploadFileResponse` object:
- `result` (boolean)
- `message` (string)
- `fileName` (stored/original name)
- `fileNameLink` (typically `../../tmp/<fileName>`)
Example shape:
```json
[
{
"result": true,
"message": "...",
"fileName": "punti-foto.csv",
"fileNameLink": "../../tmp/punti-foto.csv"
}
]
```
## Race command API (`/admin/pg/Gara.abl`)
Confirmed custom commands in `GaraSvlt`:
- `addPuntoFoto`
- `delPuntoFoto`
- `modPuntoFoto`
- `indexFoto`
- `noIndexFoto`
- `creaPuntiFoto`
- `indexCsvPisa`
- `salvaFileCsv`
Important parameters by command:
- `id_gara` for race-level operations
- `id_puntoFoto` and `id_puntoFotoIdx` for point selection
- point fields such as `descrizionePuntoFoto`, `pathRelativoFoto`, `tipoPuntoFoto`
CSV flow coupling:
1. `cmd=saveFile` uploads to `tmp/` and returns `fileName`
2. UI stores it into hidden field `fileNameOnServer_1`
3. `cmd=salvaFileCsv` copies `DOCBASE/tmp/<fileNameOnServer_1>` to `DOCBASE/admin/csv/<id_gara>.csv`
4. `cmd=indexCsvPisa` reads `admin/csv/<id_gara>.csv` via `Gara.getImpCsvFileName()` and updates matching photos
## Image retrieval behavior
`/foto/*` (`GetFileTnSvlt`):
- accepts `id_foto` query parameter, or extracts id from URL suffix pattern like `name-<id>.jpg`
- if photo not found, serves `_img/_imgNotFound.png`
- returns thumbnail by default in this servlet flow
`/fotoOriginali/*` (`GetFileOrigSvlt`):
- routes to original-file logic
- applies user/account checks (valid user, not expired, max photos)
- blocks some originals by filename markers (`_X`, `_Y`, `_Z`) depending on profile
- logs photo view events when original is served
## Known response caveat
Do not treat `result=true` as universally reliable for success semantics:
- in some error branches (`_loadImg`, `_removeImg`, `_saveFile`), code still returns `result=true` with an error message.
For robust clients, validate both:
- `result`
- `message` text + expected output field (`imgPath` / `fileName` non-empty)
## Practical automation sequence
1. Login on `/admin/menu/Menu4.abl` with `cmdIU=check`, store cookies.
2. Create/update race data on `/admin/pg/Gara.abl` with regular form commands.
3. Upload images with `cmd=loadImg`.
4. (Optional) upload CSV with `cmd=saveFile`.
5. Finalize CSV placement with `cmd=salvaFileCsv` and run `cmd=indexCsvPisa`.
6. Read thumbnails from `/foto/*` and originals from `/fotoOriginali/*`.

View file

@ -0,0 +1,679 @@
openapi: 3.0.3
info:
title: RUS Reverse-Engineered API (Races, Uploads, Auth)
version: 1.0.0
description: |
OpenAPI specification inferred from JSP/JS usage, `WEB-INF/web.xml`, and decompiled sources
in `WEB-INF/lib/*_src`.
This application is command-driven (`*.abl`) and many endpoints return server-rendered HTML.
Where the implementation returns JSON payloads (notably upload operations), schemas are modeled
explicitly from decompiled DTOs:
- `JsonUploadImageResponse { result, message, imgPath }`
- `JsonUploadFileResponse { result, message, fileName, fileNameLink }`
## Important caveats
- Authentication is session-cookie based (typically `JSESSIONID`), not JWT bearer.
- Some error branches in upload handlers still return `result: true` with an error message text.
Clients should validate both `result` and semantic fields (`imgPath`, `fileName`).
- Several command endpoints primarily render JSP/HTML, so response contracts are best-effort.
- Some deployments namespace admin page endpoints as `/admin/pg_RUS/*` instead of `/admin/pg/*`.
Example observed deployment: `https://www.regalamiunsorriso.it` links `/admin/pg_RUS/Gara.abl` from dashboard.
servers:
- url: https://your-host
description: Replace with your deployed host
tags:
- name: Authentication
description: Session login/logout and related command flows
- name: RaceAdmin
description: Admin race management (`/admin/pg/Gara.abl`) including uploads and command actions
- name: PhotoAdmin
description: Admin photo/type/log endpoints (command-driven)
- name: Media
description: Thumbnail/original photo retrieval
- name: Public
description: Public-facing login/user/photo endpoints mapped in web.xml
security:
- SessionCookieAuth: []
paths:
/admin/menu/Menu4.abl:
post:
tags: [Authentication]
summary: Admin login/logout/password command endpoint
description: |
Command-driven login servlet (`Menu4Svlt` extending `Logon4Svlt`).
Primary commands (`cmdIU`):
- `check` => login
- `login` => logout
- `np` => password-change flow
- `checkSso` => SSO branch (when enabled)
security: []
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/Menu4CommandRequest'
examples:
login:
summary: Login
value:
login: YOUR_USER
pwd: YOUR_PASSWORD
cmdIU: check
logout:
summary: Logout
value:
cmdIU: login
passwordChange:
summary: Password change flow
value:
cmdIU: np
login: YOUR_USER
pwd: YOUR_OLD_PASSWORD
responses:
'200':
description: |
Usually HTML/JSP response with redirect or rendered page; on successful login, session cookies are set.
headers:
Set-Cookie:
description: Session cookie(s), usually including `JSESSIONID`
schema:
type: string
content:
text/html:
schema:
type: string
examples:
loginOk:
summary: Typical successful login page/redirect body
value: "<html>...LOGIN_OK...</html>"
'401':
description: Authentication failure semantics are typically encoded in HTML/message, not strict HTTP 401.
/admin/pg/Gara.abl:
get:
tags: [RaceAdmin]
summary: Race admin endpoint (command/query rendering)
description: |
Command endpoint for race administration. GET is commonly used for page loads/search rendering.
Typical query parameters include `cmd`, `act`, `id_gara`, pagination fields.
parameters:
- $ref: '#/components/parameters/Cmd'
- $ref: '#/components/parameters/Act'
- $ref: '#/components/parameters/IdGara'
responses:
'200':
description: Server-rendered HTML/JSP response
content:
text/html:
schema:
type: string
post:
tags: [RaceAdmin]
summary: Race admin command endpoint (multipart and form-urlencoded)
description: |
Supports both:
1) `multipart/form-data` upload commands (`loadImg`, `removeImg`, `saveFile`)
2) `application/x-www-form-urlencoded` action commands (`addPuntoFoto`, `indexCsvPisa`, ...)
Source evidence:
- `AblServletSvlt._loadImg/_removeImg/_saveFile`
- `GaraSvlt` custom command methods
requestBody:
required: true
content:
multipart/form-data:
schema:
oneOf:
- $ref: '#/components/schemas/GaraLoadImgMultipartRequest'
- $ref: '#/components/schemas/GaraRemoveImgMultipartRequest'
- $ref: '#/components/schemas/GaraSaveFileMultipartRequest'
encoding:
imgFile:
contentType: image/*
fileName:
contentType: '*/*'
examples:
loadImg:
summary: Upload race image slot
value:
cmd: loadImg
id: 123
codImage: 1
totImgNumber: 3
removeImg:
summary: Remove race image slot
value:
cmd: removeImg
id: 123
codImage: 1
totImgNumber: 3
saveFile:
summary: Upload CSV/import file
value:
cmd: saveFile
codFile: 1
id: 0
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/GaraCommandRequest'
examples:
addPuntoFoto:
value:
cmd: addPuntoFoto
id_gara: 123
descrizionePuntoFoto: "Start"
pathRelativoFoto: "start/"
tipoPuntoFoto: "A"
indexFoto:
value:
cmd: indexFoto
id_gara: 123
id_puntoFotoIdx: 987
noIndexFoto:
value:
cmd: noIndexFoto
id_gara: 123
id_puntoFotoIdx: 987
creaPuntiFoto:
value:
cmd: creaPuntiFoto
id_gara: 123
indexCsvPisa:
value:
cmd: indexCsvPisa
id_gara: 123
salvaFileCsv:
value:
cmd: salvaFileCsv
id_gara: 123
fileNameOnServer_1: "punti-foto.csv"
responses:
'200':
description: |
Mixed response style depending on `cmd`.
- Upload commands generally return JSON array with one object.
- Many non-upload commands render HTML/JSP with server messages.
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/UploadImageResponseArray'
- $ref: '#/components/schemas/UploadFileResponseArray'
examples:
imageUploadOk:
value:
- result: true
message: "Immagine 1 Salvata"
imgPath: "../../_img/_gara/100/123_1_1700000000000.jpg"
imageUploadErrorStyle:
summary: Known caveat branch
value:
- result: true
message: "Immagine NON Salvata. Utente non valido"
imgPath: "../../"
fileUploadOk:
value:
- result: true
message: "File punti-foto.csv Salvato"
fileName: "punti-foto.csv"
fileNameLink: "../../tmp/punti-foto.csv"
text/html:
schema:
type: string
examples:
htmlCommandResponse:
value: "<html>...messaggi/bean rendering...</html>"
/admin/pg/Foto.abl:
get:
tags: [PhotoAdmin]
summary: Admin photo listing/search endpoint
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
post:
tags: [PhotoAdmin]
summary: Admin photo command endpoint
requestBody:
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/GenericCommandRequest'
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
/admin/pg/TipoGara.abl:
get:
tags: [PhotoAdmin]
summary: Admin race-type endpoint
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
post:
tags: [PhotoAdmin]
summary: Admin race-type command endpoint
requestBody:
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/GenericCommandRequest'
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
/admin/pg/LogFoto.abl:
get:
tags: [PhotoAdmin]
summary: Admin photo-log endpoint
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
post:
tags: [PhotoAdmin]
summary: Admin photo-log command endpoint
requestBody:
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/GenericCommandRequest'
responses:
'200':
description: Server-rendered HTML/JSP
content:
text/html:
schema:
type: string
/foto/{filename}:
get:
tags: [Media]
summary: Get thumbnail/photo by path; supports id_foto query
description: |
Mapped to `GetFileTnSvlt`.
Behavior:
- If `id_foto` is provided, photo is loaded by id.
- If missing, servlet may parse id from `{filename}` suffix pattern `name-<id>.<ext>`.
- If not found, fallback `_img/_imgNotFound.png`.
security:
- SessionCookieAuth: []
parameters:
- name: filename
in: path
required: true
schema:
type: string
description: Requested filename segment (also used for id parsing fallback)
- name: id_foto
in: query
required: false
schema:
type: integer
format: int64
description: Photo id (preferred)
responses:
'200':
description: Image bytes or HTML error text based on access checks
content:
image/jpeg:
schema:
type: string
format: binary
image/png:
schema:
type: string
format: binary
text/html:
schema:
type: string
examples:
blocked:
value: "Attenzione!. Questa Foto non puo' essere scaricata!!"
/fotoOriginali/{filename}:
get:
tags: [Media]
summary: Get original photo (with profile/account restrictions)
description: |
Mapped to `GetFileOrigSvlt` (delegates to original-file flow).
Includes additional checks:
- account validity/expiry/max-photo constraints
- filename marker restrictions (`_X`, `_Y`, `_Z`) by profile
- logs access events on successful original retrieval
security:
- SessionCookieAuth: []
parameters:
- name: filename
in: path
required: true
schema:
type: string
- name: id_foto
in: query
required: false
schema:
type: integer
format: int64
responses:
'200':
description: Image bytes or access-denied HTML text
content:
image/jpeg:
schema:
type: string
format: binary
image/png:
schema:
type: string
format: binary
text/html:
schema:
type: string
examples:
denied:
value: "Attenzione!. Account scaduto o raggiunto n. foto massimo"
/Logon.abl:
post:
tags: [Public]
summary: Public login endpoint
description: Mapped to `com.ablia.pg.servlet.Logon2Svlt`.
security: []
requestBody:
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PublicLogonRequest'
responses:
'200':
description: HTML/JSP response with session handling
content:
text/html:
schema:
type: string
/Users.abl:
get:
tags: [Public]
summary: Public users endpoint
responses:
'200':
description: Implementation-specific output (usually HTML/JSP)
content:
text/html:
schema:
type: string
post:
tags: [Public]
summary: Public users command endpoint
requestBody:
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/GenericCommandRequest'
responses:
'200':
description: Implementation-specific output (usually HTML/JSP)
content:
text/html:
schema:
type: string
components:
securitySchemes:
SessionCookieAuth:
type: apiKey
in: cookie
name: JSESSIONID
description: |
Session cookie set by login endpoints. Some deployments can set additional cookies.
parameters:
Cmd:
name: cmd
in: query
required: false
schema:
type: string
description: Command token for the servlet command-dispatch model
Act:
name: act
in: query
required: false
schema:
type: string
description: Secondary action token used by page flows
IdGara:
name: id_gara
in: query
required: false
schema:
type: integer
format: int64
schemas:
Menu4CommandRequest:
type: object
properties:
login:
type: string
pwd:
type: string
format: password
cmdIU:
type: string
enum: [check, login, np, checkSso, checkCC, ckcclnk, cmcc, ni]
actIU:
type: string
cmd2:
type: string
act2:
type: string
sso:
type: string
required: [cmdIU]
PublicLogonRequest:
type: object
properties:
login:
type: string
pwd:
type: string
cmdIU:
type: string
enum: [check, login, np, checkSso, checkCC, ckcclnk, cmcc]
cmd:
type: string
description: May also route custom commands like `logout` in `Logon2Svlt`
GenericCommandRequest:
type: object
properties:
cmd:
type: string
act:
type: string
cmd2:
type: string
act2:
type: string
_id:
type: string
_id_name:
type: string
pageNumber:
type: integer
totPageNumber:
type: integer
flgReport:
type: string
additionalProperties: true
GaraCommandRequest:
allOf:
- $ref: '#/components/schemas/GenericCommandRequest'
- type: object
properties:
cmd:
type: string
enum:
- addPuntoFoto
- delPuntoFoto
- modPuntoFoto
- indexFoto
- noIndexFoto
- creaPuntiFoto
- indexCsvPisa
- salvaFileCsv
- aggiornaThreadMsg
- search
- md
- ni
- refresh
id_gara:
type: integer
format: int64
id_puntoFoto:
type: integer
format: int64
id_puntoFotoIdx:
type: integer
format: int64
descrizionePuntoFoto:
type: string
pathRelativoFoto:
type: string
tipoPuntoFoto:
type: string
fileNameOnServer_1:
type: string
pathBase:
type: string
descrizione:
type: string
dataGaraInizio:
type: string
format: date
dataGaraFine:
type: string
format: date
GaraLoadImgMultipartRequest:
type: object
required: [cmd, imgFile, id, codImage]
properties:
cmd:
type: string
enum: [loadImg]
imgFile:
type: string
format: binary
id:
type: integer
format: int64
description: Race id (maps to bean primary key in upload flow)
codImage:
type: integer
description: Image slot index (UI uses 1..3)
totImgNumber:
type: integer
description: Total image slots for timestamp rotation logic
GaraRemoveImgMultipartRequest:
type: object
required: [cmd, id, codImage]
properties:
cmd:
type: string
enum: [removeImg]
id:
type: integer
format: int64
codImage:
type: integer
totImgNumber:
type: integer
GaraSaveFileMultipartRequest:
type: object
required: [cmd, fileName]
properties:
cmd:
type: string
enum: [saveFile]
fileName:
type: string
format: binary
description: Field used by JS helper (`Ab.saveFile`)
codFile:
type: integer
id:
type: integer
format: int64
JsonUploadImageResponse:
type: object
properties:
result:
type: boolean
message:
type: string
imgPath:
type: string
required: [result, message, imgPath]
JsonUploadFileResponse:
type: object
properties:
result:
type: boolean
message:
type: string
fileName:
type: string
fileNameLink:
type: string
required: [result, message, fileName, fileNameLink]
UploadImageResponseArray:
type: array
minItems: 1
maxItems: 1
items:
$ref: '#/components/schemas/JsonUploadImageResponse'
UploadFileResponseArray:
type: array
minItems: 1
maxItems: 1
items:
$ref: '#/components/schemas/JsonUploadFileResponse'