javascriptweb-scrapingbase64decodingprotobuf.js

How to decode Base64-encoded Protobuf data in JavaScript without a schema?


I am trying to scrape data from the betting site etipos.sk. The API response includes a Base64-encoded Protobuf string in the ReturnValue field.

Here’s an example of the API response:


{
  Result: 1,
  Token: '4c6a71e287a5499a54e7c284a5d9bd4d',
  ReturnValue: 'CrIICq8ICg0KAjY1EgdGbG9yYmFsGNUGIv0BChIKBHgxNjASBsSMZXNrbxoCNjUS5gEK4wEKBXh4MzQ2EglTdXBlcmxpZ2EaBHgxNjAqyAEIyZ5WEh9Ccm5vIC0gRkIgSHVycmljYW4gS2FybG92eSBWYXJ5IgcIgN2ombgyKgg1MjM3MjAwNzKBAQhZEg9IbGF2bsOpIHN0w6F2a3kabAoMMTlkMTc1NDk3NTc1EgZaw6FwYXMyUAjnwtdTEgZaw6FwYXMY+sINIhMKCTQ5NDYzOTMzNRIBMR1xPQpAIhMKCTQ5NDYzOTMzNhIBWB2Pwq1AIhMKCTQ5NDYzOTMzNxIBMh3XoxBAWAJgAjoFeHgzNDZQAWDVBiL3AQoRCgJ4NxIHRsOtbnNrbxoCNjUS4QEK3gEKBnh4NzQyOBIORi1MaWlnYSwgxb5lbnkaAng3Kr8BCKKdVxIVRXJhdmlpa2luZ2l0IC0gU0ItUHJvIgcIwIHNr6kyKgg1MTc5MjI3NTKBAQhZEg9IbGF2bsOpIHN0w6F2a3kabAoMMTlkMTc3NzI2NDU5EgZaw6FwYXMyUAj7x99UEgZaw6FwYXMY3PoaIhMKCTUwMDM1MDg5NhIBMR1I4bo/IhMKCTUwMDM1MDg5NxIBWB3D9aBAIhMKCTUwMDM1MDg5OBIBMh1xPZpAWAJgAjoGeHg3NDI4UAFg1QYipgIKGQoEeDE2NRINxaB2YWrEjWlhcnNrbxoCNjUSiAIKhQIKBnh4NzQ1NBIdVW5paG9ja2V5IFByaW1lIExlYWd1ZSwgxb5lbnkaBHgxNjUq1QEIk6RXEitSZWQgQW50cyBSeWNoZW5iZXJnIFdpbnRlcnRodXIgLSBadWcgVW5pdGVkIgcIgPPE06oyKgg1MTgzNDk2NzKBAQhZEg9IbGF2bsOpIHN0w6F2a3kabAoMMTlkMTc3OTI1NTA1EgZaw6FwYXMyUAiB2+tUEgZaw6FwYXMYrqwFIhMKCTUwMTEwMDA5MxIBMR2PwvVAIhMKCTUwMTEwMDA5NBIBWB0fhetAIhMKCTUwMTEwMDA5NRIBMh1I4Zo/WAJgAjoGeHg3NDU0UAFg1QYi9wEKEwoCeDYSCcWgdsOpZHNrbxoCNjUS3wEK3AEKBHh4NDYSEVN1cGVybGlnYW4sIMW+ZW55GgJ4Niq8AQjUtFcSFFJvbm5ieSAtIFRhYnkgRkMgSUJLIgcIwLuEs6kyKgg1MTc4ODE5OTKBAQhZEg9IbGF2bsOpIHN0w6F2a3kabAoMMTlkMTc4MTQxNDYzEgZaw6FwYXMyUAiX8vhUEgZaw6FwYXMYjr0IIhMKCTUwMTc5OTMyMRIBMR2PwtU/IhMKCTUwMTc5OTMyMBIBWB0AALBAIhMKCTUwMTc5OTMxORIBMh0AAFBAWAJgAjoEeHg0NlABYNUGEhYInf//////////ARIHWsOhcGFzeRgBGAQ=',
  Type: 'GetWebStandardEventsResponse'
}

The value I need is hidden in the ReturnValue field. I can decode the Base64 string, but I'm unable to parse the resulting Protobuf data without a schema.

Here’s the JavaScript code I’ve tried:

const axios = require('axios');

const start = async()=>{
    const response = await axios.post(
        'https://tipkurz.etipos.sk/WebServices/Api/SportsBettingService.svc/GetWebStandardEvents',
        {
            'LanguageID': 17,
            'Token': '4c6a71e287a5499a54e7c284a5d9bd4d',
            'CategoryID': '65',
            'Top': 50
        }
    )
    const base64String = response.data.ReturnValue;
    const decodedString = atob(base64String); // Decode Base64
    console.log(decodedString); // Output the decoded string
}
start()

I was able to decode message using cyberchef

Despite successfully decoding the Base64 string, I cannot parse the resulting Protobuf data without knowing the schema. Any assistance on how to achieve this would be greatly appreciated!


Solution

  • Here's how to decode the response:

    1. Install protobuf.js ( npm install protobufjs ).
    2. Go to https://tipkurz.etipos.sk/zapasy.
    3. Locate apiContract.js:
      • Devtools (F12), press Ctrl + P (open file) > type apiContract.js.
      • OR find it under Sources > webpack:///modules/eTipCommon/api/proto/apiContract.js
    4. Download/save apiContract.js and place it in the same folder as this script:

    const root = require('./apiContract.js');
    const axios = require('axios');
    
    function decodeResponse(base64String) {
        const buffer = Buffer.from(base64String, 'base64');
        return root.GetWebStandardEventsResponse.decode(buffer);
    }
    
    async function start() {
        const response = await axios.post(
            'https://tipkurz.etipos.sk/WebServices/Api/SportsBettingService.svc/GetWebStandardEvents',
            {
                'LanguageID': 17,
                'Token': '427d2c7c9eb0eaed4eff336beb21aec0',
                'CategoryID': 'x130',
                'Top': 50
            }
        );
    
        const base64String = response.data.ReturnValue;
        const decodedObject = decodeResponse(base64String);
        
        console.log(JSON.stringify(decodedObject));
    }
    
    start()