<?php
require("../../app/xss_protection_encoding.php");
define('AGENT_NOT_HEARD_PATH', '/parablu/reports/');
define('OVERVIEW_REPORT_PATH', '/parablu/bkpOverview/');
$allowedFunctions = ['moveForView', 'deleteRedundantFile', 'mergeFile', 'uploadFileSync', 'uploadFolderSync', 'deleteSyncFile', 'getEmailAddress', 'getAccessTokenGoogle', 'getAccessToken', 'getAccessTokenBilling', 'getAccessTokenAdminConsent', 'uploadInfectedFile', 'downloadFailedUsersDump', 'downloadExportUnusualActivityHistoryToExcel'];
function moveForView($filePath, $ext) {
  $destinationPath = '/var/www/portal/assets/document/';
  $fileName = basename($filePath);
  $newFileName = pathinfo($fileName, PATHINFO_FILENAME) . '.' . $ext;
  $newFilePath = $destinationPath . $newFileName;
  // Debugging output
  echo "Current working directory: " . getcwd() . PHP_EOL;
  echo "Checking file path: '$filePath'" . PHP_EOL;
  // Empty the destination directory
  if (is_dir($destinationPath)) {
    $files = scandir($destinationPath);
    foreach ($files as $file) {
        if ($file !== '.' && $file !== '..') {
            $fileToDelete = $destinationPath . $file;
            if (is_file($fileToDelete)) {
                unlink($fileToDelete);
            }
        }
    }
  } else {
    echo "Error: Destination directory does not exist: $destinationPath";
    return;
  }
  // Trim and resolve real path
  $filePath = trim($filePath);
  $realFilePath = realpath($filePath);
  if (!$realFilePath) {
      // Additional checks if `realpath()` fails
      echo "Error: Unable to resolve the file path." . PHP_EOL;
      if (!file_exists($filePath)) {
          echo "Reason: File does not exist at the provided path: $filePath" . PHP_EOL;
      } else {
          echo "Reason: File exists but could not resolve the real path. Possible reasons:" . PHP_EOL;
          echo "- Hidden characters in the path." . PHP_EOL;
          echo "- Permissions issues preventing access to the file." . PHP_EOL;
          echo "- File path is a broken symbolic link." . PHP_EOL;
      }
      return;
  }
  if (!is_dir($destinationPath)) {
      echo "Error: Destination directory does not exist: $destinationPath";
      return;
  }
  if (!is_writable($destinationPath)) {
      echo "Error: Destination directory is not writable: $destinationPath";
      return;
  }
  $command = "cp " . escapeshellarg($realFilePath) . " " . escapeshellarg($newFilePath);
  $output = shell_exec($command);
  if (!file_exists($newFilePath)) {
      echo "Error: Failed to copy file. Command output: $output";
      return;
  }
  echo "File successfully copied to $newFilePath";
}
function deleteRedundantFile() {
  $destinationPath = '/var/www/portal/assets/document/';
  if (is_dir($destinationPath)) {
    $files = scandir($destinationPath);
    foreach ($files as $file) {
        if ($file !== '.' && $file !== '..') {
            $fileToDelete = $destinationPath . $file;
            if (is_file($fileToDelete)) {
                unlink($fileToDelete);
            }
        }
    }
  } else {
    echo "Error: Destination directory does not exist: $destinationPath";
    return;
  }
}
function mergeFile($directoryName) {
  $finalFile = $directoryName;
  $fp = fopen($finalFile, 'wb');
  $chunkIndex = 0;
  while (file_exists("$finalFile.part$chunkIndex")) {
    $chunk = file_get_contents("$finalFile.part$chunkIndex");
    fwrite($fp, $chunk);
    unlink("$finalFile.part$chunkIndex"); // optional: remove chunk after merging
    $chunkIndex++;
  }
  fclose($fp);
}
function uploadFileSync($cloudName, $directoryName) {
  $basePath = "/parablu/".$cloudName."/sync-upload/Portal/";
  $path = $basePath . $directoryName . "/";
  if (!is_dir($path)) {
      if (!mkdir($path, 0777, true)) {
          $result = array(
              'result' => 'fail',
              'msg' => 'Failed to create directory'
          );
          die(json_encode($result));
      }
  }
  $fileName = $_POST['fileName'];
  $chunkIndex = intval($_POST['chunkIndex']);
  $totalChunks = intval($_POST['totalChunks']);
  $fileTmp = $_FILES['file']['tmp_name'];
  $targetFile = $path . $fileName . ".part" . $chunkIndex;
  if (move_uploaded_file($fileTmp, $targetFile)) {
      chmod($targetFile, 0777);
      // If all chunks are uploaded, merge them
      if ($chunkIndex === $totalChunks - 1) {
          $finalFile = $path . $fileName;
          $out = fopen($finalFile, 'wb');
          for ($i = 0; $i < $totalChunks; $i++) {
              $chunkFile = $path . $fileName . ".part" . $i;
              if (!file_exists($chunkFile)) {
                  $result = array(
                      'result' => 'fail',
                      'msg' => 'Missing chunk ' . $i
                  );
                  die(json_encode($result));
              }
              $in = fopen($chunkFile, 'rb');
              while ($buffer = fread($in, 8192)) {
                  fwrite($out, $buffer);
              }
              fclose($in);
              unlink($chunkFile); // Clean up chunk after merging
          }
          fclose($out);
          chmod($finalFile, 0777);
          $response = array(
              'result' => 'success',
              'msg' => 'File uploaded and merged successfully'
          );
          echo json_encode($response);
          exit;
        } else {
          $response = array(
              'result' => 'success',
              'msg' => "Chunk $chunkIndex uploaded successfully"
          );
          echo json_encode($response);
          exit;
      }
  } else {
      $response = array(
          'result' => 'fail',
          'msg' => 'Failed to upload chunk'
      );
      echo json_encode($response);
      exit;
  }
}
function uploadFolderSync($cloudName, $directoryName) {
  $basePath = "/parablu/".$cloudName."/sync-upload/Portal/";
  $path = $basePath . $directoryName . "/";
  if (!is_dir($path)) {
      if (!mkdir($path, 0777, true)) {
          $result = array(
              'result' => 'fail',
              'msg' => 'Failed to create directory'
          );
          die(json_encode($result));
      }
  }
  $fileName = $_POST['fileName'];
  $chunkIndex = intval($_POST['chunkIndex']);
  $totalChunks = intval($_POST['totalChunks']);
  $fileTmp = $_FILES['file']['tmp_name'];
  $targetFile = $path . $fileName . ".part" . $chunkIndex;
  if (move_uploaded_file($fileTmp, $targetFile)) {
      chmod($targetFile, 0777);
      // If all chunks are uploaded, merge them
      if ($chunkIndex === $totalChunks - 1) {
          $finalFile = $path . $fileName;
          $out = fopen($finalFile, 'wb');
          for ($i = 0; $i < $totalChunks; $i++) {
              $chunkFile = $path . $fileName . ".part" . $i;
              if (!file_exists($chunkFile)) {
                  $result = array(
                      'result' => 'fail',
                      'msg' => 'Missing chunk ' . $i
                  );
                  die(json_encode($result));
              }
              $in = fopen($chunkFile, 'rb');
              while ($buffer = fread($in, 8192)) {
                  fwrite($out, $buffer);
              }
              fclose($in);
              unlink($chunkFile); // Clean up chunk after merging
          }
          fclose($out);
          chmod($finalFile, 0777);
          $response = array(
              'result' => 'success',
              'msg' => 'File uploaded and merged successfully'
          );
          echo json_encode($response);
          exit;
      } else {
          $response = array(
              'result' => 'success',
              'msg' => "Chunk $chunkIndex uploaded successfully"
          );
          echo json_encode($response);
          exit;
      }
  } else {
      $response = array(
          'result' => 'fail',
          'msg' => 'Failed to upload chunk'
      );
      echo json_encode($response);
      exit;
  }
}
function deleteSyncFile($destinationPath) {
  unlink($destinationPath);
return;
}
function getEmailAddress($token){
  $url = 'https://people.googleapis.com/v1/people/me?personFields=emailAddresses&access_token='.$token;
  $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
  curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
  $response = curl_exec($ch);
  $responseData = json_decode($response, true);
  $userEmail = json_encode($responseData['emailAddresses'][0]['value']);
  echo "res : ".json_encode($responseData['emailAddresses'][0]['value']);
  //$emailAddress = $responseData['id_token'];
  return $userEmail;
  }
function getAccessTokenGoogle($cId, $rUri, $cSec, $code, $returnUrl) {
  $url = 'https://accounts.google.com/o/oauth2/token';
$headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
$body = http_build_query([
  'client_id' => $cId,
  'redirect_uri' => $rUri,
  'client_secret' => $cSec,
  'code' => $code,
  'grant_type' => 'authorization_code'
]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$responseData = json_decode($response, true);
echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
if (isset($responseData['access_token']) && isset($responseData['refresh_token']) && isset($responseData['id_token'])) {
$accessToken = $responseData['access_token'];
$refreshToken = $responseData['refresh_token'];
$authToken = $responseData['id_token'];

echo "<script>
    localStorage.setItem('access_token', '$accessToken');
    localStorage.setItem('refresh_token', '$refreshToken');
    localStorage.setItem('auth_token', '$authToken');
    window.location.href = decodeURIComponent('$returnUrl');
  </script>
";
} else {
echo "
  <script>
      window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
      window.location.href = '$returnUrl';
  </script>
";
}
curl_close($ch);
}
function getAccessToken($cId, $rUri, $cSec, $code, $returnUrl, $errorReturnUrl = null) {
  $url = 'https://login.microsoftonline.com/common/oauth2/token';
  $headers = [
      'Content-Type: application/x-www-form-urlencoded',
      'Cache-Control: no-cache',
      'Pragma: no-cache'
  ];
  if (empty($code)) {
    $errorMessage = 'User canceled or no authorization code received.';
    echo "
        <script>
            console.error('OAuth2 Token Error: $errorMessage');
            // Store error in localStorage
            localStorage.setItem('auth_error_reason', 'no_code');
            localStorage.setItem('auth_error_message', '$errorMessage');
            window.location.href = '$errorReturnUrl';
        </script>
    ";
    exit;
  }
  $body = http_build_query([
      'client_id' => $cId,
      'redirect_uri' => $rUri,
      'client_secret' => $cSec, // This secret that could be invalid
      'code' => $code,
      'grant_type' => 'authorization_code',
      'resource' => 'https://graph.microsoft.com/'
  ]);
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
  $response = curl_exec($ch);
  $responseData = json_decode($response, true);
  curl_close($ch);
  echo "<script>
  console.log('OAuth2 Token Exchange');
  console.log('Request URL:', '" . $url . "');
  console.log('Request Headers:', " . json_encode($headers) . ");
  console.log('Request Body (string):', `" . addslashes($body) . "`);
  console.log('Raw API Response:', " . json_encode($responseData) . ");
  </script>";
  if (isset($responseData['access_token']) && isset($responseData['refresh_token'])) {
      $accessToken = $responseData['access_token'];
      $refreshToken = $responseData['refresh_token'];
      echo "<script>
            localStorage.removeItem('auth_error_reason');
            localStorage.removeItem('auth_error_message');
            localStorage.setItem('access_token', '$accessToken');
            localStorage.setItem('refresh_token', '$refreshToken');
            window.location.href = decodeURIComponent('$returnUrl');
          </script>
      ";
  } else {
      $errorReason = 'unknown_token_error';
      $errorMessage = 'Failed to get access token or refresh token.';
      if (isset($responseData['error'])) {
          $apiError = $responseData['error'];
          $apiDescription = isset($responseData['error_description']) ? str_replace("'", "\'", $responseData['error_description']) : 'No description provided.';          
          if ($apiError === 'invalid_client' || $apiError === 'unauthorized_client') {
              $errorReason = 'invalid_client_secret';
              $errorMessage = "Authentication failed. Invalid Client ID or Client Secret. Details: $apiDescription";
          } else {
              $errorReason = $apiError;
              $errorMessage = "OAuth Token Error: $apiDescription";
          }
      }
      echo "
          <script>
              // Store error details in localStorage
              localStorage.setItem('auth_error_reason', '$errorReason');
              localStorage.setItem('auth_error_message', '$errorMessage');

              console.error('OAuth2 Token Error: $errorMessage');
              // Redirect without query parameters
              window.location.href = '$errorReturnUrl';
          </script>
      ";
  }
}
function getAccessTokenBilling($tid, $cId, $rUri, $cSec, $code, $returnUrl) {
  $url = 'https://login.microsoftonline.com/'.$tid.'/oauth2/v2.0/token';
  $headers = [
      'Content-Type: application/x-www-form-urlencoded',
      'Cache-Control: no-cache',
      'Pragma: no-cache'
  ];
  if (empty($code)) {
    $errorMessage = 'User canceled or no authorization code received.';
    echo "
        <script>
            console.error('OAuth2 Token Error: $errorMessage');
            // Store error in localStorage
            localStorage.setItem('auth_error_reason', 'no_code');
            localStorage.setItem('auth_error_message', '$errorMessage');
            window.location.href = '$returnUrl';
        </script>
    ";
    exit;
  }
  $body = http_build_query([
      'client_id' => $cId,
      'scope' => 'BackupRestore-Control.ReadWrite.All',
      'redirect_uri' => $rUri,
      'client_secret' => $cSec,
      'code' => $code,
      'grant_type' => 'authorization_code'
]);
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
  $response = curl_exec($ch);
  $responseData = json_decode($response, true);
  curl_close($ch);
  echo "<script>
  console.log('OAuth2 Token Billing');
  console.log('Request URL:', '" . $url . "');
  console.log('Request Headers:', " . json_encode($headers) . ");
  console.log('Request Body (string):', `" . addslashes($body) . "`);
  console.log('Raw API Response:', " . json_encode($responseData) . ");
  </script>";
  if (isset($responseData['access_token'])) {
      $accessToken = $responseData['access_token'];
      echo "<script>
            localStorage.removeItem('auth_error_reason');
            localStorage.removeItem('auth_error_message');
            localStorage.setItem('access_token_billing', '$accessToken');
            window.location.href = decodeURIComponent('$returnUrl');
          </script>
      ";
  } else {
      $errorReason = 'unknown_token_error';
      $errorMessage = 'Failed to get access token or refresh token.';
      if (isset($responseData['error'])) {
          $apiError = $responseData['error'];
          $apiDescription = isset($responseData['error_description']) ? str_replace("'", "\'", $responseData['error_description']) : 'No description provided.';
          if ($apiError === 'invalid_client' || $apiError === 'unauthorized_client') {
              $errorReason = 'invalid_client_secret';
              $errorMessage = "Authentication failed. Invalid Client ID or Client Secret. Details: $apiDescription";
          } else {
              $errorReason = $apiError;
              $errorMessage = "OAuth Token Error: $apiDescription";
          }
      }
      echo "
          <script>
              // Store error details in localStorage
              localStorage.setItem('auth_error_reason', '$errorReason');
              localStorage.setItem('auth_error_message', '$errorMessage');

              console.error('OAuth2 Token Error: $errorMessage');
              // Redirect without query parameters
              window.location.href = '$returnUrl';
          </script>
      ";
  }
}
function getAccessTokenAdminConsent($cId, $rUri, $cSec, $code) {
        $url = 'https://login.microsoftonline.com/common/oauth2/token';
    $headers = [
        'Content-Type: application/x-www-form-urlencoded',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
    $body = http_build_query([
        'client_id' => $cId,
        'redirect_uri' => $rUri,
        'client_secret' => $cSec,
        'code' => $code,
        'grant_type' => 'authorization_code',
        'resource' => 'https://graph.microsoft.com/'
    ]);
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
    $response = curl_exec($ch);
    $responseData = json_decode($response, true);
    echo "<script>
    console.log('OAuth2 Token Exchange');
    console.log('Request URL:', '" . $url . "');
    console.log('Request Headers:', " . json_encode($headers) . ");
    console.log('Request Body (string):', `" . addslashes($body) . "`);
    console.log('Raw API Response:', " . json_encode($responseData) . ");
    </script>";
    if (isset($responseData['access_token']) && isset($responseData['refresh_token'])) {
    $accessToken = $responseData['access_token'];
    $refreshToken = $responseData['refresh_token'];

    echo "
        <script>
            window.opener.postMessage({
                access_token: '$accessToken',
                refresh_token: '$refreshToken'
            }, '*');
            window.close();
        </script>
    ";
} else {
    echo "
        <script>
            window.opener.postMessage({ error: 'Failed to get access token or refresh token' }, '*');
            window.close();
        </script>
    ";
}
    curl_close($ch);
}
function uploadInfectedFile(){
//if (isset($_FILES['updateFileName'])) {
                        $path = "/parablu/RWSampleFiles/";
                        if (!is_dir($path)) {
                    $result = array(
                                'result' => 'fail',
                                'msg' => 'No Directory Found'
                    );
                    die(json_encode($result));
                }
                    $file_name = $_FILES['file']['name'];
                    $file_tmp = $_FILES['file']['tmp_name'];
                    $file_type = $_FILES['file']['type'];
                    $file_size = $_FILES['file']['size'];
                    $file_ext = strtolower(end(explode('.', $_FILES['file']['name'])));
                    $file = $path . $file_name;
                    //$this->log("file :  ".$file,"info");
                    $errors = [];
                        if ($errors) {
                                //$this->log("ERRORS WHILE UPLOADING".json_encode($errors),"info");
                                $result = array(
                                    'result' => 'fail',
                                    'msg'    => 'Failed to upload file'
                                );
                                die(json_encode($result));
                        }
                            if (empty($errors)) {
                                //$this->log("success ","info");
                                move_uploaded_file($file_tmp, $file);
                                chmod($file, 0777);
                                                $response = array(
                                        'result' => 'success',
                                        'msg'    => 'File uploaded succesfully'
                                    );
                                    echo json_encode($response);
                                    exit;
                                        }else{
                                                $response = array(
                                'result' => 'fail',
                                'msg'    => 'Failed to upload file'
                            );
                            echo json_encode($response);
                            exit;
                                        }
        //}
}
//dump after bulk operation
function downloadFailedUsersDump() {
  $filePath = AGENT_NOT_HEARD_PATH.'Users_Block_Fail.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=Users_Fail.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
//dump after bulk odb target excel
function downloadOdbExcel() {
  $filePath = AGENT_NOT_HEARD_PATH.'OdbMappingFailedUsers.xlsx';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=OdbMappingFailedUsers.xlsx');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('report/'.$_GET['from'].'?result=404'));
  }
}
function downloadExportUnusualActivityHistoryToExcel($userName) {
  $filePath = OVERVIEW_REPORT_PATH.'UnusualActivity_Audit_Overview_'.$userName.'.xls';
  if (file_exists($filePath)) {
    header('Content-Type: application/csv');
    header('Content-Disposition: attachment; filename=UnusualActivity_Audit_Overview_'.$userName.'.xls');
    header('Pragma: no-cache');
    ob_clean();
    readfile($filePath);
  } else {
    header('Location: '.Url:: basePath('/report/'.$_GET['from'].'?result=404'));
  }
}
if (isset($_GET['function'])) {
  $functionName = XSS_encode($_GET['function']);
  if (in_array($functionName, $allowedFunctions)) {
    $params = $_GET['params'] ?? [];
    if (is_string($params)) {
      $params = explode(',', $params);
    }
    try {
      call_user_func_array($functionName, $params);
    } catch (Exception $e) {
            echo "Error executing function: ".$e -> getMessage();
    }
  } else {
        echo "Function '$functionName' is not allowed.";
  }
} else {
    echo "No function specified.";
}
?>
