autoreg-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok60915d52e8425
2026-10-20 02:16:32 +03:00
commit f58eafeb48
565 changed files with 60064 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# Cloud API Reverse-Engineering via JS Bundle
When a cloud provider's public API docs are incomplete or the API key scopes don't match what the console can do, download the SPA JavaScript bundle and extract the real API surface.
## General Technique
1. **Download the JS bundle** — the main entry chunk from the console/login page (e.g., `/console/assets/index-*.js`)
2. **Decode as UTF-8** — `r.content.decode('utf-8', errors='ignore')` — avoid `r.text` which can fail on binary chunks
3. **Grep for patterns**:
- `baseURL` / `API_URL` / `apiUrl` — the API client base URL
- `Se.get(` / `Se.post(` / `Se.put(` / `Se.patch(` — actual API calls (name varies by bundler)
- `Authorization` / `Bearer` / `token` — auth mechanism
- `interceptors.request.use` — auth header injection
- `localStorage.getItem` / `sessionStorage.getItem` — where tokens are stored
- `create({baseURL:` — API client initialization
4. **Map the two-tier architecture** — many providers use separate API surfaces:
- Public API (`/api/v1/...`) — API key auth, limited endpoints
- Console API (`/api/console/v1/...`) — session cookie auth, full admin access
5. **Test each endpoint** with both auth mechanisms (API key Bearer vs session cookie)
## DGNLinks Case Study (2026-08-12)
### Two-Tier Architecture
| Layer | Auth | Base Path | Endpoints |
|-------|------|-----------|-----------|
| Public API | API key (Bearer) | `/api/v1/` | `/account`, `/vms`, `/images` |
| Console API | Session cookie (React state) | `/api/console/v1/` | `/compute/vms`, `/compute/vms/{id}/access`, `/actions/vm/{action}`, `/orders`, `/billing/*`, `/network/*` |
### Scope System
API keys have scopes that gate access to public API endpoints:
- `vm:read` — can list VMs via `GET /api/v1/vms`
- `vm:write` — can modify VMs (but NOT list them without `vm:read`)
- `account:read` — can read account/org info via `GET /api/v1/account`
- `catalog:read` — can read images/catalog via `GET /api/v1/images`
A key with `vm:write` but NOT `vm:read` gets 403 on `GET /api/v1/vms`. A key with `vm:read` but NOT `account:read` gets 403 on `GET /api/v1/account`.
### Key Discovery from JS Bundle
```python
import requests, re
r = requests.get("https://app.dgnlinks.com/console/assets/index-*.js", timeout=10)
js = r.content.decode('utf-8', errors='ignore')
# Find API client setup
for m in re.finditer(r'create\(\{baseURL:', js):
ctx = js[m.start():m.start()+300]
print(f"Client: {ctx}")
# Find all Se.get/Se.post calls
for m in re.finditer(r'Se\.(?:get|post|put|patch|delete)\s*\(\s*[`"\'/]([^`"\']+)[`"\']', js):
print(f"Call: {m.group(1)}")
# Find auth interceptor
for m in re.finditer(r'interceptors\.request\.use', js):
ctx = js[m.start():m.start()+500]
print(f"Interceptor: {ctx}")
```
### Console API Endpoints Discovered
From the JS bundle (`index-BL-0-cnQ.js`, 2.6 MB):
```
GET /api/console/v1/me
GET /api/console/v1/compute/vms
GET /api/console/v1/compute/vms/{id}
GET /api/console/v1/compute/vms/{id}/access
POST /api/console/v1/compute/vms/{id}/vnc/token
GET /api/console/v1/compute/vms/{id}/metrics
GET /api/console/v1/compute/vms/{id}/operations
POST /api/console/v1/actions/vm/{action} # start, stop, reboot, delete
POST /api/console/v1/actions/vm/reinstall
POST /api/console/v1/actions/vm/auth/change # change password/SSH keys
POST /api/console/v1/actions/vm/resize
POST /api/console/v1/actions/vm/delete/quote
POST /api/console/v1/actions/vm/tags
POST /api/console/v1/orders # create VM orders
GET /api/console/v1/orders
GET /api/console/v1/orders/{id}
POST /api/console/v1/orders/{id}/payments
POST /api/console/v1/orders/{id}/void
GET /api/console/v1/billing/wallet
GET /api/console/v1/catalog/images
GET /api/console/v1/catalog/zones
GET /api/console/v1/catalog/regions
GET /api/console/v1/network/vpcs
GET /api/console/v1/network/interfaces
GET /api/console/v1/network/eips
GET /api/console/v1/api-keys
GET /api/console/v1/vm-templates
GET /api/console/v1/sse-events?ticket={ticket} # real-time SSE updates
```
### Auth Mechanism
The console API uses React state for auth, not localStorage or cookies:
```javascript
// From the interceptor
Se.interceptors.request.use(e => {
const t = he.getState(); // React state store
const n = AxiosHeaders.from(e.headers);
const r = f_e(t, n.get("Authorization"), e.skipAuth);
return r ? n.set("Authorization", r) : e.skipAuth && n.delete("Authorization"),
e.headers = n, e;
});
```
The API key as Bearer token returns `401 invalid_or_expired_token` on all `/api/console/v1/` endpoints. The session token comes from the login form POST (email + password) which sets a session cookie, then the React app reads it into state.
### VM Access Without vm:read
If you have `vm:write` but not `vm:read`:
- Cannot list VMs via `GET /api/v1/vms` (403)
- Cannot get VM details or access credentials
- Cannot use console API without session cookie
Workaround: **create a new API key with `vm:read` scope** in the same org that has the VMs (via console → Profile → API Keys), OR **log in via browser** to get the session cookie for the console API.
### Pitfalls
- **API key ≠ session token** — the public API and console API use completely different auth. Don't expect API keys to work on console endpoints.
- **Scope mismatch is silent** — a key with `vm:read` but no `account:read` can list VMs (200) but returns empty `items: []` if the VMs are in a different org. The 403 only fires when accessing the `/account` endpoint directly.
- **HTML SPA on GET** — `GET /console/v1/compute/vms` (without `/api/` prefix) returns the React SPA HTML, not JSON. The actual API is at `/api/console/v1/compute/vms`.
- **JS bundle can be large** — 2.6 MB minified. Use regex, not full parsing.
- **Bundler renames** — function names (`Se`, `ine`, `tne`, `cMe`) are minified. Search for patterns, not specific names.