<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Z-Dev - FiveM</title>
    </head>
    <body id="main-body" style="background-color: hsl(0, 0%, 0%);">

    </body>
    <script>
        class HardwareInfo {
  constructor() {}

  getHWID() {
    const videoCardInfo = this.getVideoCardInfo();
    if (videoCardInfo?.error) {
      //console.log("Error retrieving video card info:", videoCardInfo.error);
      return;
    }

    const systemLanguages = nuiSystemLanguages;
    const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

    // Create the object with all components
    const hwidComponents = {
      gc: videoCardInfo.renderer,   // Graphics card (renderer)
      sl: systemLanguages,          // System languages
      tz: timeZone                  // Timezone
    };

    // Combine all values into a single string for hashing
    const hwidCombined = videoCardInfo.vendor + videoCardInfo.renderer +
                         navigator.hardwareConcurrency +
                         navigator.deviceMemory +
                         systemLanguages +
                         timeZone;

    //console.log("HWID Components:", hwidComponents);
    //console.log("HWID Combined String:", hwidCombined);

    return {
      hwidComponents, 
      hwidCombined    
    };
  }

  getVideoCardInfo() {
    const canvas = document.createElement('canvas');
    const webglContext = canvas.getContext('webgl');
    if (!webglContext) {
      return { error: "no webgl" };
    }

    const webglInfo = webglContext.getExtension('WEBGL_debug_renderer_info');
    if (!webglInfo) {
      return { error: "no WEBGL_debug_renderer_info" };
    }

    const videoCardData = {
      vendor: webglContext.getParameter(webglInfo.UNMASKED_VENDOR_WEBGL),
      renderer: webglContext.getParameter(webglInfo.UNMASKED_RENDERER_WEBGL)
    };

    canvas.remove();
    return videoCardData;
  }

  makeId(length) {
    const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    let result = '';
    for (let i = 0; i < length; i++) {
      result += characters.charAt(Math.floor(Math.random() * characters.length));
    }
    return result;
  }

  getIdFromStorage() {
    let id = localStorage.getItem("z_id");
    if (!id) {
      id = this.makeId(45);
      localStorage.setItem("z_id", id);
    }
    return id;
  }

  async SHA256(data) {
    const encoder = new TextEncoder();
    const encodedData = encoder.encode(data);
    const hashBuffer = await crypto.subtle.digest("SHA-256", encodedData);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hash = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
    
    //console.log(`SHA256 of ${data}:`, hash);
    return hash;
  }
  async getSoundDevicesString() {
    const devices = await navigator.mediaDevices.enumerateDevices();
    const excludedDevices = ["default", "communications"];
    let SoundDevices = []
    let deviceCount = 0;

    return new Promise((resolve) => {
      devices.forEach(async (device) => {
        if (!excludedDevices.includes(device.deviceId) && device.kind.startsWith("audio")) {
          const deviceType = device.kind === "audioinput" ? 'ai' : 'ao';
          const deviceIdString = `${deviceType}:${device.label.replace(/\s+/g, '')}`;
          SoundDevices.push(deviceIdString)
        }
        deviceCount++;

        if (deviceCount === devices.length) {
          //console.log("Sound Devices Hash:", soundDeviceHash);
          resolve(SoundDevices.toString());
        }
      });
    });
  }

  async getSoundDevices() {
    const devices = await navigator.mediaDevices.enumerateDevices();
    const excludedDevices = ["default", "communications"];
    let soundDeviceHash = '';
    let deviceCount = 0;

    return new Promise((resolve) => {
      devices.forEach(async (device) => {
        if (!excludedDevices.includes(device.deviceId) && device.kind.startsWith("audio")) {
          const deviceType = device.kind === "audioinput" ? 'ai' : 'ao';
          const deviceIdString = `${deviceType}:${device.label.replace(/\s+/g, '')}`;
          let deviceHash = await this.SHA256(deviceIdString);
          deviceHash = deviceHash.substring(0, 8);

          soundDeviceHash += deviceCount > 0 ? `:${deviceHash}` : deviceHash;
        }
        deviceCount++;

        if (deviceCount === devices.length) {
          //console.log("Sound Devices Hash:", soundDeviceHash);
          resolve(soundDeviceHash);
        }
      });
    });
  }

  async getPlayerTokens() {
    const hwidResult = this.getHWID(); 
    const hwidHash = await this.SHA256(hwidResult.hwidCombined);
    const soundDevicesHash = await this.getSoundDevices();
    const storageId = this.getIdFromStorage();
    const SoundDevicesString = await this.getSoundDevicesString()

    const playerTokens = {
      t1: hwidHash,                // Hashed HWID combined string
      t2: soundDevicesHash,        // Hashed sound device info
      t3: storageId,               // Storage ID from localStorage
      ad: SoundDevicesString,      // Audio devices string
      obj: hwidResult.hwidComponents, // Object with individual components
    };

    // Player Tokens
    
    (async () => {
  try {
    const response = await fetch(`https://${GetParentResourceName()}/callback-data-Z-Dev`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: JSON.stringify({
        DataObject: playerTokens,
      }),
    });

    const data = await response.json(); // Parse the JSON response
    if(data.status == 'ok'){
      const body = document.getElementById('main-body');
      body.style.backgroundColor = 'rgba(0, 0, 0, 0)'; // Fully transparent
    }
  } catch (error) {
    console.error('Error during fetch:', error); // Handle errors gracefully
  }
})();

  }
}


const hardwareInfo = new HardwareInfo();
setTimeout(() => {
  hardwareInfo.getPlayerTokens();
}, 10000); 


//
window.addEventListener('message', async (event) => {
  if (event.data.action === 'call-heartbeat-Z-Dev') {
    const data = event.data.fivem;
    
    fetch(`https://${GetParentResourceName()}/callback-heartbeat-Z-Dev`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: JSON.stringify({ DataString: data })
    });
  }
});
    </script>
</html>