This commit is contained in:
+84
-59
@@ -1,92 +1,117 @@
|
||||
# Personal Profile
|
||||
|
||||
This document covers two unrelated profile-adjacent surfaces:
|
||||
This document covers two profile-adjacent surfaces:
|
||||
|
||||
1. **Personal profile** — an HTML page on the WebView host, scraped for display.
|
||||
1. **Personal details** — full name, email, mobile number and National ID, shown on the login details screen.
|
||||
2. **Profile image management** — three encrypted-API endpoints (`P40`/`P41`/`P42`) that fetch, upload, and delete the avatar.
|
||||
|
||||
---
|
||||
|
||||
## 1. Personal Profile (HTML scrape)
|
||||
## 1. Personal Details
|
||||
|
||||
Fetch the user's personal profile details. This endpoint returns an HTML page; data is extracted via HTML scraping.
|
||||
The details come from two sources and are fetched once at login, then cached (`MibProfileClient.kt`).
|
||||
|
||||
### Endpoint
|
||||
| Field | Source |
|
||||
|---|---|
|
||||
| Full name | `A41` login init response — `fullName` |
|
||||
| Email | Alias suggestions — type `1` (falls back to `A41` `email`) |
|
||||
| Mobile number | Alias suggestions — type `0` |
|
||||
| National ID | Alias suggestions — type `3` |
|
||||
|
||||
```
|
||||
GET https://faisamobilex-wv.mib.com.mv/personalProfile
|
||||
### Full name — `A41`
|
||||
|
||||
The `A41` login init response (see [02-login.md](02-login.md)) carries the user's details at the root:
|
||||
|
||||
```json
|
||||
{
|
||||
"fullName": "Mohamed Ali",
|
||||
"email": "user@example.com",
|
||||
"lastLoginTime": "2026-05-16 15:10:25",
|
||||
"customerImgHash": "<image hash>",
|
||||
"roleName": "Consumer Premium"
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Session cookies only — no additional AJAX headers required.
|
||||
### Alias Suggestions — `getAliasTypes`
|
||||
|
||||
```
|
||||
Cookie: mbmodel=IOS-1.0; xxid=<session_xxid>; IBSID=<session_xxid>; mbnonce=<nonceGenerator>; time-tracker=597
|
||||
POST https://faisamobilex-wv-v2.mib.com.mv/ajaxAlias/getAliasTypes
|
||||
```
|
||||
|
||||
### Response
|
||||
WebView session cookies and AJAX headers (see [README](README.md)). Empty POST body.
|
||||
|
||||
**Content-Type:** `text/html; charset=UTF-8`
|
||||
|
||||
The page contains an `<h5>` with the user's full name and `<span>` elements with labelled fields.
|
||||
|
||||
### Parsing Strategy
|
||||
|
||||
**Full name** — extracted from:
|
||||
```html
|
||||
<h5 class="mb-1 text-dark fw-semibold">Mohamed Ali</h5>
|
||||
```
|
||||
Referer: https://faisamobilex-wv-v2.mib.com.mv/Alias/Alias?dashurl=1
|
||||
```
|
||||
|
||||
Regex:
|
||||
```kotlin
|
||||
Regex("""<h5 class="mb-1 text-dark fw-semibold">\s*([^<]+)\s*</h5>""")
|
||||
The suggestions belong to the **currently selected** profile and differ between personal and business profiles. Select the personal profile (`profileType: "0"`) with `P47` first (see [03-accounts.md](03-accounts.md)).
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"responseCode": "2",
|
||||
"reasonCode": "203",
|
||||
"reasonText": "Alias Types Search Success.",
|
||||
"data": [
|
||||
{ "id": 0, "aliasTypeName": "Mobile Number", "suggestedAlias": "+9609600001" },
|
||||
{ "id": 1, "aliasTypeName": "E-Mail", "suggestedAlias": "user@example.com" },
|
||||
{ "id": 3, "aliasTypeName": "National ID", "suggestedAlias": "A000001" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Labelled fields** — each follows this pattern:
|
||||
```html
|
||||
<span ...><b ...>Username:</b ...>...<span ...>myusername</span>
|
||||
```
|
||||
|
||||
Regex (used for each label):
|
||||
```kotlin
|
||||
Regex(
|
||||
"""<span[^>]*>\s*<b[^>]*>\s*$label\s*</b[^>]*>.*?<span[^>]*>([^<]+)</span>""",
|
||||
setOf(RegexOption.DOT_MATCHES_ALL, RegexOption.IGNORE_CASE)
|
||||
)
|
||||
```
|
||||
|
||||
### Extracted Fields
|
||||
|
||||
| Label in HTML | Field | Description |
|
||||
| `id` | `aliasTypeName` | Used as |
|
||||
|---|---|---|
|
||||
| `Username:` | `username` | Login username |
|
||||
| `Email:` | `email` | Registered email address |
|
||||
| `Mobile no:` | `mobile` | Registered mobile number |
|
||||
| `Enrolled:` | `enrolled` | Enrollment date or status |
|
||||
| `0` | Mobile Number | Mobile number (with `+960` prefix) |
|
||||
| `1` | E-Mail | Email |
|
||||
| `3` | National ID | ID card number |
|
||||
|
||||
Combined with the `fullName` from the `<h5>`:
|
||||
A type may be missing from `data` when the user has no value for it.
|
||||
|
||||
```kotlin
|
||||
data class MibPersonalProfile(
|
||||
val fullName: String,
|
||||
val username: String,
|
||||
val email: String,
|
||||
val mobile: String,
|
||||
val enrolled: String
|
||||
)
|
||||
### Registered Aliases — `ajaxAlias/main`
|
||||
|
||||
```
|
||||
POST https://faisamobilex-wv-v2.mib.com.mv/ajaxAlias/main
|
||||
```
|
||||
|
||||
### Notes
|
||||
Lists the user's registered Favara aliases. Not consumed by the app.
|
||||
|
||||
- Returns `null` if the response cannot be parsed (network error or unexpected HTML structure).
|
||||
- This endpoint does not have a JSON equivalent — scraping is the only method.
|
||||
Body: `page=1&search=&searchAccount=&searchAliasType=&sort=AlsId&sortDir=asc&start=1&end=20&includeCount=1`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"reasonText": "Favara ID Search Success.",
|
||||
"data": [
|
||||
{
|
||||
"AlsBfy": { "Tp": "MSISDN", "Id": "+9609600001" },
|
||||
"BfyNm": "Mohamed",
|
||||
"BfySnm": "Ali",
|
||||
"CdtrAcct": { "Acct": "90100000000000000", "FinInstnId": "MADVMVMV" },
|
||||
"AcctHldrId": "A000001",
|
||||
"AcctHldrIdTp": "IDENTITY_NUMBER",
|
||||
"AcctHldrTp": "INDIVIDUAL",
|
||||
"AdrLine": "<address>",
|
||||
"Ctry": "MDV",
|
||||
"RegDtTm": "2026-05-12T20:07:44",
|
||||
"AlsSt": "ACTIVE",
|
||||
"PhneNb": "+9609600001",
|
||||
"EmailAdr": "user@example.com"
|
||||
}
|
||||
],
|
||||
"Pg": { "Size": 20, "TtlElms": 1, "TtlPgs": 1, "Nmb": 0 }
|
||||
}
|
||||
```
|
||||
|
||||
`AlsBfy.Tp` is the alias type, e.g. `MSISDN` or `NATIONAL_ID`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Profile Image Management
|
||||
|
||||
The avatar lives on the **encrypted API** (`faisanet.mib.com.mv`), not the WebView host. Three `sfunc=n` route paths cover fetch, upload, and delete. All three follow the standard encrypted-request format (see [01-encryption.md](01-encryption.md) and [02-login.md](02-login.md)) and include the standard `baseData` fields (`nonce`, `appId`, `sodium`, `routePath`, `xxid`).
|
||||
The avatar lives on the **encrypted API** (`faisamobilex-smvc-v2.mib.com.mv`), not the WebView host. Three `sfunc=n` route paths cover fetch, upload, and delete. All three follow the standard encrypted-request format (see [01-encryption.md](01-encryption.md) and [02-login.md](02-login.md)) and include the standard `baseData` fields (`nonce`, `appId`, `sodium`, `routePath`, `xxid`).
|
||||
|
||||
| `routePath` | Operation | Source |
|
||||
|---|---|---|
|
||||
@@ -101,10 +126,10 @@ The same conceptual value — "the hash that identifies a customer's avatar" —
|
||||
| Source endpoint | Field name |
|
||||
|---|---|
|
||||
| `A41` login init (`operatingProfiles[]`) | `customerImage` |
|
||||
| `A41` login init (root) | `customerImgHash` |
|
||||
| `C41` registration init (root) | `customerImgHash` |
|
||||
| `ajaxBeneficiary/main` (contacts list) | `customerImgHash` |
|
||||
|
||||
Both are non-empty hash strings that can be passed straight into `P41` as `imageHash`. Treat them as the same value with two names.
|
||||
Both are non-empty hash strings that can be passed straight into `P41` as `imageHash`. Treat them as the same value with two names. Contact photos use a separate route, `B46` (see [09-contacts.md](09-contacts.md)).
|
||||
|
||||
### Fetch — `routePath: P41`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user