AI context/memory from Claude Code sessions covering all infrastructure: JARVIS, NovaCPX, DO sites, Proxmox, FusionPBX, MediaStack, and project feedback/preferences.
3.4 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| feedback-yealink-api | Yealink T48S web API quirks — RSA/AES login, token-gated writes, correct page/field names for SIP account config |
|
Yealink T48S web API (firmware 66.86.0.15) — complete working flow:
Login (PKCS1v15 + AES-CBC hybrid)
- GET
/servlet?m=mod_listener&p=login&q=loginForm— fetch RSA public key (g_rsa_n,g_rsa_e) and initialJSESSIONIDcookie - Generate random 16-byte AES key + IV; encrypt plaintext
{rand};{JSESSIONID};{password}with AES-128-CBC zero-padding (NOT PKCS7), base64 result →pwd - RSA-encrypt AES key hex string and IV hex string separately with PKCS1v15 →
rsakey,rsaiv- Critical: encrypt the ASCII hex string (e.g.
"a1b2c3...") not raw bytes — Yealink'spkcs1pad2usescharCodeAtper character - Critical: AES key/IV hex must be lowercase
- Critical: encrypt the ASCII hex string (e.g.
- POST
username=admin&pwd=<b64>&rsakey=<hex>&rsaiv=<hex>to/servlet?m=mod_listener&p=login&q=loginwithJSESSIONIDcookie - Returns
{"authstatus":"done"}on success; cookie jar updates with new JSESSIONID
Lockout: 3 failed attempts → ~10 min lockout (polling the login page also resets the timer — stop ALL requests to the phone during lockout)
SIP Account Config (account-register page)
- Page:
account-register(NOTaccount-basic— that page only has anonymous-call advanced fields) - Load: GET
/servlet?m=mod_data&p=account-register&q=load - Write: POST
/servlet?m=mod_data&p=account-register&q=write&token=<g_strToken>- Token is required — without it returns 403; with it returns 200 + empty
_RES_INFO_div (that empty response IS success) - Token comes from
g_strTokenvariable in the loaded page HTML
- Token is required — without it returns 403; with it returns 200 + empty
Correct field names for SIP account 1:
| Field | Value |
|---|---|
var_accountID |
0 (0-indexed) |
AccountEnable |
1 |
AccountLabel |
display label |
AccountDisplayName |
caller ID name |
AccountRegisterName |
SIP auth username (e.g. 1000) |
AccountUserName |
SIP username (e.g. 1000) |
server1 |
SIP server IP (e.g. 134.209.72.226) |
port1 |
SIP port (e.g. 5080) |
Transport1 |
0 = UDP |
Expires1 |
registration expiry seconds |
AccountPassword |
AES-encrypted password (same AES key/IV as login) |
Password encryption for writes: Same AES-CBC approach as login — encrypt plaintext password bytes with zero-padding, base64 result → AccountPassword. Send same rsakey + rsaiv alongside.
Autoprovision Trigger
GET /servlet?m=mod_data&p=settings-autop&q=autopnow&token=<g_strToken> → returns {"ret":"ok","data":"3"} on success
Reboot
POST /servlet?m=mod_data&p=settings-upgrade&q=write&type=reboot
SIP Registration Status
Load page contains JS: ccStatus = g_json.ParseJSON(...) with JSON like {"Account1":"1000@134.209.72.226:2"} — status codes: 0=disabled, 1=registered, 2=registering, 3=failed
Why: All this was reverse-engineered from Yealink's commonjs.js (pkcs1pad2 function) across multiple sessions after many failed approaches (textbook RSA, wrong plaintext format, wrong field names, missing token).
How to apply: Use this as the reference any time we script Yealink T48S configuration via its web API. Scripts are saved at /tmp/yfix_server.py and /tmp/ydiag_write.py (on PVE1) as working examples.