Files
DatBrowser/app/Browser/Jobs/Hellcase/HellcaseJob.php
Matthias Guillitte 6b9b5a60e9
All checks were successful
Push image to registry / build-image (push) Successful in 3m21s
Should fix HellcaseJob login
2025-07-02 12:29:36 +02:00

403 lines
15 KiB
PHP

<?php
namespace App\Browser\Jobs\Hellcase;
use App\Browser\BrowserJob;
use App\Browser\Components\Hellcase\MainNav;
use App\Browser\JobDebugScreenshot;
use App\Browser\Jobs\Hellcase\HellcaseLoginQrCode;
use App\Models\JobArtifact;
use App\Models\JobRun;
use App\Notification\NotificationBody\Hellcase\HellcaseNotificationDailyFreeBody;
use App\Notification\NotificationBody\Hellcase\HellcaseNotificationLoginBody;
use App\Notification\Notifications\Hellcase\HellcaseNotificationDailyFree;
use App\Notification\Notifications\Hellcase\HellcaseNotificationLogin;
use App\Notification\Notifications\JobDebugNotification;
use App\Notification\Notifications\JobErrorNotification;
use App\Notification\Providers\AllNotification;
use Facebook\WebDriver\WebDriverBy;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
use Illuminate\Support\Facades\Log;
use Laravel\Dusk\Browser;
class HellcaseJob extends BrowserJob implements ShouldBeUniqueUntilProcessing
{
private const STEAM_LOGIN_THRESHOLD = 5 * 60; // 5 minutes
private const APPROXIMATIVE_RUNNING_MINUTES = 2;
protected JobRun $jobRun;
public function __construct($jobId = 2)
{
parent::__construct($jobId);
}
public function run(Browser $browser): ?JobRun
{
Log::info("Running HellcaseJob");
$this->jobRun = new JobRun([
"job_id" => $this->jobId,
"success" => false,
]);
$this->jobRun->save();
$browser->visit('https://hellcase.com');
$browser->waitForText("CASES", 30, true);
$this->removePopups($browser);
sleep(5);
$this->signin($browser);
try {
$this->joinFreeGiveaways($browser);
} catch (\Exception $e) {
$this->jobRun->success = false;
$this->jobRun->save();
AllNotification::send(new JobErrorNotification($this->jobId, "Erreur lors de la participation aux concours gratuits : " . $e->getMessage()));
}
$this->getDailyFree($browser);
$this->jobRun->success = true;
$this->jobRun->save();
Log::info("HellcaseJob run ended");
return $this->jobRun;
}
/**
* @inheritDoc
*/
public function runTest(Browser $browser): ?JobRun
{
try {
$browser->visit('https://hellcase.com');
$browser->waitForText("CASES", 30, true);
$this->removePopups($browser);
sleep(2);
$this->signin($browser);
return $this->makeSimpleJobRun(
true,
"Connexion réussie",
"Datboi a réussi à se connecter sur Hellcase"
);
} catch (\Exception $e) {
return $this->makeSimpleJobRun(
false,
"Connexion échouée",
"Datboi n'a pas réussi à se connecter sur Hellcase :\n" . $e->getMessage()
);
}
}
protected function signin(Browser $browser)
{
try {
$browser->clickAtXPath('//button[.//span[text() = "Sign in"]]');
} catch (\Exception $e) {
return;
}
sleep(5);
$browser->waitForText("Sign in with Steam", 30, true);
sleep(3);
$browser->driver->findElement(WebDriverBy::xpath("//button[. = 'Sign in with Steam']"))->click();
sleep(5);
// QR CODE SCANNING
try {
$browser->waitForTextIn("div", "Or sign in with QR", 30, true);
sleep(10);
try {
$qrCode = $browser->driver->findElement(WebDriverBy::xpath('//div[./*[contains(text(), "Or sign in with QR")]]'));
} catch (\Exception $e) {
$browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
AllNotification::send(new JobDebugNotification($this->jobId, "Le QR code de la page de connexion de Steam n'a pas été trouvé"));
throw $e;
}
// Wait to be redirected to the Steam login page, while waiting take a new screenshot every 30 seconds
$isBackOnHellcase = false;
$secondsCounter = 0;
while (!$isBackOnHellcase && $secondsCounter < self::STEAM_LOGIN_THRESHOLD) {
// Take a screenshot of the QR code and send it
$qrCode->takeElementScreenshot(HellcaseLoginQrCode::getImgFileAbsolutePath());
AllNotification::send(
new HellcaseNotificationLogin(
$this->jobId,
new HellcaseNotificationLoginBody()
)
);
try {
$browser->waitForLocation("https://hellcase.com", HellcaseLoginQrCode::QR_CODE_VALIDITY); // The QR code is only valid for 20 seconds
} catch (\Exception $e) {
$secondsCounter += HellcaseLoginQrCode::QR_CODE_VALIDITY; // we've waited for QR_CODE_VALIDITY seconds
continue;
}
$isBackOnHellcase = true;
}
} catch (\Exception $e) {
// If the QR code is not found, we are not on the QR code page
Log::debug("Exception because qrcode not found : " . $e);
$isBackOnHellcase = true;
} catch (\Throwable $e) {
// If the QR code is not found, we are not on the QR code page
Log::debug("Exception because qrcode not found : " . $e);
$isBackOnHellcase = true;
}
if ($isBackOnHellcase) {
// Click a button that says "sign in"
$browser->waitForText("By signing into steam.loginhell.com through Steam", 30, true);
$browser->clickAtXPath('//input[@id = "imageLogin"]');
sleep(20);
}
}
private function joinFreeGiveaways(Browser $browser)
{
try {
$buttons = $browser->driver->findElements(WebDriverBy::xpath('//a[text() = "Join for free"]'));
} catch (\Exception $e) {
$browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
AllNotification::send(new JobDebugNotification($this->jobId, "No join for free buttons found"));
return;
}
if (sizeof($buttons) == 0) {
$this->jobRun->addArtifact(new JobArtifact([
"name" => "Pas de concours joignable",
"content" => ""
]));
}
try {
// $nextSlideButton = $browser->driver->findElement(WebDriverBy::xpath('//button[@class="_button_1ygbm_7 _next_1ygbm_24"]'));
$nextSlideButton = "Button next slide is deactivated";
} catch (\Exception $e) {
$browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
AllNotification::send(new JobDebugNotification($this->jobId, "No next slide button found"));
return;
}
foreach ($buttons as $button) {
// Click the next slide button if the button is not clickable
$clickedFailsCounter = 0;
while ($clickedFailsCounter < 7 && $clickedFailsCounter >= 0) {
try {
$button->click();
} catch (\Exception $e) {
$clickedFailsCounter++;
try {
// $nextSlideButton->click();
} catch (\Exception $_) {}
sleep(3);
continue;
}
$clickedFailsCounter = -1;
}
sleep(5); // Wait a bit for loading
$this->joinGiveaway($browser);
$browser->within(new MainNav, function (Browser $browser) {
$browser->goToHome();
});
}
}
private function joinGiveaway(Browser $browser)
{
$joinButton = $browser->driver->findElement(WebDriverBy::xpath('//button[span[contains(text(), "Join for free")]]'));
$joinButton->click();
sleep(3);
// JobRun
// Get the elements text containing class starting with giveaway-entity-prize__
$prizeElement = $browser->driver->findElements(WebDriverBy::xpath('//div[starts-with(@class, "giveaway-entity-prize__")]'));
// Join their text
$prize = "";
foreach ($prizeElement as $element) {
$prize .= $element->getText() . "\n";
}
$this->jobRun->addArtifact(new JobArtifact([
"name" => "Rejoint le concours",
"content" => "Pour tenter de gagner le prix : \n" . $prize
]));
}
private function getDailyFree(Browser $browser)
{
$browser->visit('https://hellcase.com/dailyfree');
try {
$browser->waitForText("Get Daily free loot", 30, true);
} catch (\Exception $e) {
return; // Pobably means we do not have access to a daily free loot
}
// Do we fill the conditions ?
if (sizeof(value: $browser->driver->findElements(WebDriverBy::xpath('//p[contains(text(), "Fulfill the conditions below")]'))) > 0) {
$this->fillDailyFreeConditions($browser);
}
// If we see "availible in 20 HR 49 MIN", parse the hours and minute and reschedule
$availibleInButton = $browser->driver->findElement(WebDriverBy::xpath('//button[contains(@class, "daily-free-banner__button")]'));
if ($availibleInButton->getAttribute("disabled") == "true") {
$hours = $availibleInButton->getText();
// If the text is like "in 26 sec." we need to put one minute
if (str_contains(strtolower($hours), "seconds")) {
$browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
AllNotification::send(new JobDebugNotification($this->jobId, "I hate niggers"));
// $this->reschedule(1);
sleep(60);
return $this->getDailyFree($browser);
}
$hours = explode(" ", $hours);
$minutes = $hours[4];
$hours = $hours[2];
$this->jobRun->addArtifact(new JobArtifact([
"name" => "Cadeau gratuit pas encore disponible",
"content" => "Le cadeau gratuit journalier sera disponible dans {$hours} heures et {$minutes} minutes."
]));
$this->reschedule($hours * 60 + $minutes + 1);
return;
}
// Click the dailyfree button
$availibleInButton->click();
sleep(15);
$browser->waitForText("Your drop", 30, true);
$lootElement = $browser->driver->findElement(WebDriverBy::xpath('//div[contains(@class, "daily-free-win-bonus")]'));
$lootElement->takeElementScreenshot(HellcaseDailyFreeScreenshot::getImgFileAbsolutePath());
$this->reschedule((24 * 60) - ($this::APPROXIMATIVE_RUNNING_MINUTES / 2)); // Reschedule in 24hr -1min
AllNotification::send(
new HellcaseNotificationDailyFree($this->jobId, new HellcaseNotificationDailyFreeBody())
);
}
/**
* Must be on the dailyfree page
* @param \Laravel\Dusk\Browser $browser
* @throws \Exception
* @return void
*/
private function fillDailyFreeConditions(Browser $browser)
{
// 1. See what conditions we need to fullfill
$conditions = [];
$conditionsDivs = $browser->driver->findElements(WebDriverBy::xpath('//*[@class = "daily-free-requirement__heading-left"]'));
for ($i = 0; $i < sizeof($conditionsDivs); $i++) {
$conditionDiv = $conditionsDivs[$i];
// See if the element has the completed class
$conditions[$i] = [
"isFilled" => str_contains($conditionDiv->getAttribute("class"), "completed"),
"text" => $conditionDiv->getText()
];
}
if (sizeof($conditions) == 0) {
throw new \Exception("No dailyfree conditions found");
}
if (!$conditions[0]["isFilled"]) {
$this->changeSteamProfilePicture($browser);
}
if (!$conditions[1]["isFilled"]) {
$this->changeSteamProfileToPublic($browser);
}
}
/**
*
* Must be on the dailyfree page
* @param \Laravel\Dusk\Browser $browser
* @return void
*/
private function changeSteamProfilePicture(Browser $browser)
{
// Get all of the availible image link
$images = $browser->driver->findElements(WebDriverBy::xpath('//a[@class = "daily-free-user-requirement-avatar-item"]'));
// Download the image from the second link in a special folder
$imageLink = $images[1]->getAttribute("href");
// Download the image in app/Browser/downloads/
$imagePath = base_path("app/Browser/downloads/Hellcase/pp.png");
file_put_contents($imagePath, file_get_contents($imageLink));
$this->goToSteamProfileSettings($browser);
// Wait for and click "Avatar"
$this->waitForAndClickText($browser, "Avatar");
// Wait for and click "Upload your avatar"
$browser->waitForText("Upload your avatar", 30, true);
// $browser->clickAtXPath('//*[contains(text(), "Upload your avatar")]');
// Upload the downloaded image
$browser->attach('input[type="file"]', $imagePath);
// Wait for and click save
$this->waitForAndClickText($browser, "Save");
// Go back to dailyfree
$browser->visit('https://hellcase.com/dailyfree');
sleep(10);
try {
// wait and click "Check the condition"
$this->waitForAndClickText($browser, "Check the condition");
$browser->waitForText("Your Steam profile avatar does not match any of the ones specified in the", 30, true);
} catch (\Exception $e) {
// If the text is not found, the condition is filled
return;
}
}
private function changeSteamProfileToPublic(Browser $browser)
{
$this->goToSteamProfileSettings($browser);
// Wait for and click "Privacy Settings"
$this->waitForAndClickText($browser, "Privacy Settings");
$dropdownButton = $browser->driver->findElement(WebDriverBy::xpath('//div[text() = "My profile"]/div'));
$dropdownButton->click();
sleep(2);
// Div that contains the visible class ath the body root an element with public text
$publicOption = $browser->driver->findElement(WebDriverBy::xpath('/body/div[contains(@class, "visible")]/div[contains(text(), "Public")]'));
$publicOption->click();
// Go back to dailyfree
$browser->visit('https://hellcase.com/dailyfree');
}
/**
* From the dailyfree page
* @param \Laravel\Dusk\Browser $browser
* @return void
*/
private function goToSteamProfileSettings(Browser $browser)
{
// Get the link that has text "Steam profile"
$steamProfileLink = $browser->driver->findElement(WebDriverBy::xpath('//a[contains(text(), "Steam profile")]'));
$browser->visit($steamProfileLink->getAttribute("href"));
$browser->waitForText("Level");
// Click "Edit Profile
$browser->clickAtXPath('//*[contains(text(), "Edit Profile")]');
}
protected function removePopups(Browser $browser)
{
// $browser->script('document.querySelector("div.app-modal")[0].remove();');
// $browser->driver->executeScript('document.querySelector("div.app-modal")[0].remove();');
}
}