Checking your win by inwi balance on a terminal

Here's how you can check your win data usage on a terminal because <note to self: insert convincing reason here before publishing>

Time for some recon. I fired off the Firefox network devtools and started inspecting. There are two endpoints of interest:

  • Login endpoint (/api/v1/auth/login): exchanges a username/password combo for a set of tokens
  • Offer detail endpoint (/api/v1/subscriptions/<ID>/offer-detail): returns statistics about the subscription

After decoding the JWT access token returned by the login endpoint, I notice that its exp claim has a generous time to live of about 7 days. The refresh token lasts twice as long. For starters I decided to use this set of tokens instead of writing code that actually logs me in, it might come in handy if they ever decide to slap a captcha on the login form. For the record, here's what the login response looks like:


{
  "account": {
    "email": "yours.truly@domain.ext",
    "firstName": "Yours",
    "lastName": "Truly",
    "accountIdSF": "XXXXXXXXXXXXXXXXXX",
    ...
  },
  "subscriptions": [
    {...}
  ],
  "carts": [],
  "tokens": {
    "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "accessToken": "eyJ...",
    "expiresIn": 604800,
    "refreshToken": "eyJ...",
    "refreshExpiresIn": 1296000,
    "tokenType": "Bearer"
  }
}

Grab the accessToken, refreshToken and accountIdSF fields, we'll be using them from here on out.

The second endpoint contains the information we need. We're gonna request it by sending a typical Bearer token-powered GET request to the endpoint above, while making sure to use the accountIdSF value as a subscription ID in the URL.


$ curl https://api.win.ma/api/v1/subscriptions/XXXXXXXXXXXXXXXXXX/offer-detail -H 'Authorization: Bearer eyJhb...'

Buried in its JSON response is an array of assets, each with the following structure, abbreviated to only include the relevant portions:


{
  "accountId": "XXXXXXXXXXXXXXXXXX",
  "type": "OTHER",
  "name": "Internet 4G",
  ...,
  "balance": {
    "consumedValue": "4171424572",
    "defaultValue": "50000000000",
    "defaultUnitValue": "BYTE",
    "expireDate": "2025-05-28T23:45:35.000+0000",
    "labelBalanceAr": "4G  أنترنيت",
    "labelBalanceFr": "Forfait Internet 4G",
    "displayorder": 100,
    "consumedUnit": "BYTE",
    ...
  },
  "dateCycleStart": "2024-10-28T22:45:35.000+0000",
  "dateCycleEnd": "2025-04-28T22:45:35.000+0000",
  "dateCycleFutureStart": "2025-04-28T22:45:35.000+0000",
  "dateCycleFutureEnd": "2025-05-28T22:45:35.000+0000",
  "dateOfferEnd": "2025-05-28T22:45:35.000+0000",
  "oneTimeBaseCharge": 0
},

So we'll need to traverse the array in question and look for this entry, then parse out the balance.consumedValue and balance.defaultValue fields. Nothing some good old PHP can't handle:


$balance = array_values(
    array_filter($offerDetails->assets, fn($asset) => $asset->name === 'Internet 4G')
)[0]->balance;
printf("Until %s\n", $balance->expireDate);
printf(
    "%.2f MB / %.2f MB (%.2f %%)\n",
    $balance->restValue / 1000 / 1000,
    $balance->defaultValue / 1000 / 1000,
    $balance->restValue / $balance->defaultValue * 100.0
);

The schrewdly perceptive readers will notice that I'm dividing by 1000 to display the values in a human-readable form. As it turns out, a 50 Go subscription is stored as 50 * 1000 * 1000 (50000000000) instead of 50 * 1024 * 1024 (52428800) for some unknown reason. This means that I'm only getting about 47.7 gigabytes per month though I will have to measure that more thoroughly to be sure.

Refreshing expired access tokens can be done by sending them to the https://api.win.ma/api/v1/auth/refresh-token endpoint as a GET query parameter:


function refreshTokens()
{
    $tokens = json_decode(file_get_contents(__DIR__ . '/win-forfait.json'));
    $ch = curl_init('https://api.win.ma/api/v1/auth/refresh-token?refreshToken=' . $tokens->refreshToken);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_RETURNTRANSFER => true,
    ]);
    $response = curl_exec($ch);
    if($response === false)
    {
        echo "Failed to refresh tokens:\n";
        echo curl_error($ch), "\n";
        echo "Try logging in with php {$argv[0]} --login\n";
        exit(1);
    }

    file_put_contents(__DIR__ . '/win-forfait.json', $response);
    echo "Tokens refreshed\n";
}

And last but not least, logging in is a matter of sending an email and password JSON request to the https://api.win.ma/api/v1/auth/login endpoint:


$ curl https://api.win.ma/api/v1/auth/login \
    -H 'Content-Type: application/json' \
    --data '{"email": "yours.truly@domain.ext", "password": "..."}'

I couldn't figure out how to securely prompt the user for a password in PHP so I'll leave that as an exercise for the reader.

And with that you can have a command-line PHP script that you can use to monitor your internet usage! Full script available in this gist: https://gist.github.com/azihassan/6f0e1ad62a84a962386361609bc5cca4

Areas of improvement:

  • A caching mechanism
  • A way to check passes
  • A way to safely input passwords

Commentaires

Posts les plus consultés de ce blog

Writing a fast(er) youtube downloader

Decrypting .eslock files

Viewing imgur through Duckduckgo