diff --git a/lib/Service/DomainService.php b/lib/Service/DomainService.php index ad7b4804f660557b540333ad4dfd49fc23557e58..4e1aac71e5474e6e0f39a170908a55d21675ee3c 100644 --- a/lib/Service/DomainService.php +++ b/lib/Service/DomainService.php @@ -57,7 +57,7 @@ class DomainService { * Check if an email belongs to a custom blacklist domain. */ public function isDomainInCustomBlacklist(string $email, IL10N $l): bool { - $domains = $this->getDomainsFromFile(self::DISPOSABLE_DOMAINS_FILE, $l); + $domains = $this->getDomainsFromLargeFile(self::DISPOSABLE_DOMAINS_FILE, $l); return $this->isDomainInList($email, $domains); } @@ -77,7 +77,7 @@ class DomainService { $cleanRelatedDomains = array_map(fn ($relatedDomain) => preg_replace('/[\x00-\x1F\x7F]/', '', $relatedDomain), $relatedDomains); // Get existing domains from the file - $domains = $this->getDomainsFromFile(self::DISPOSABLE_DOMAINS_FILE, $l); + $domains = $this->getDomainsFromLargeFile(self::DISPOSABLE_DOMAINS_FILE, $l); // Merge, deduplicate, and sanitize $newDomains = array_unique(array_merge($domains, [$cleanDomain], $cleanRelatedDomains)); @@ -139,6 +139,70 @@ private function getDomainsFromFile(string $filename, IL10N $l): array { throw new \RuntimeException($l->t('The email could not be verified. Please try again later.')); } } + +/** + * Get domains from a file. + */ + private function getDomainsFromLargeFile(string $filename, IL10N $l): array { + try { + // Get the file object + $file = $this->getDomainsFile($filename); + + // Write the file content to a temporary file + $tempFilePath = tempnam(sys_get_temp_dir(), 'nc_'); + file_put_contents($tempFilePath, $file->getContent()); + + // Open the temporary file for streaming + $handle = fopen($tempFilePath, 'r'); + if (!$handle) { + unlink($tempFilePath); // Clean up if opening fails + $this->logger->warning("File $filename not found. Returning an empty domain list."); + return []; + } + + $buffer = ''; + $insideArray = false; + $result = []; + + // Read the file in chunks and parse it incrementally + while (!feof($handle)) { + $chunk = fread($handle, 8192); // Read 8KB at a time + $buffer .= $chunk; + + // Start processing when the array opening bracket '[' is detected + if (!$insideArray && strpos($buffer, '[') !== false) { + $insideArray = true; + $buffer = substr($buffer, strpos($buffer, '[') + 1); + } + + // Parse individual elements from the JSON array + while (($pos = strpos($buffer, ',')) !== false || strpos($buffer, ']') !== false) { + $delimiter = strpos($buffer, ',') !== false ? strpos($buffer, ',') : strpos($buffer, ']'); + $jsonElement = substr($buffer, 0, $delimiter); + + // Clean and add the parsed element to the result array + $jsonElement = trim($jsonElement, "\" \n\r\t"); + if (!empty($jsonElement)) { + $result[] = $jsonElement; + } + + $buffer = substr($buffer, $delimiter + 1); + if (strpos($buffer, ']') === 0) { + fclose($handle); + unlink($tempFilePath); // Clean up the temporary file + return $result; // Return the parsed array + } + } + } + + fclose($handle); + unlink($tempFilePath); // Clean up the temporary file + return $result; + } catch (\Throwable $e) { + $this->logger->error("Error reading $filename: " . $e->getMessage()); + throw new \RuntimeException($l->t('The email could not be verified. Please try again later.')); + } + } /** * Save domains to a file. */ diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index c1001ec62e2a44e3794f2ca94d6fc8b400a7c167..e4532ff28eafad6f7210287777a6441704d44ab9 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -137,7 +137,6 @@ class RecoveryEmailService { } if ($this->domainService->isDomainInCustomBlacklist($recoveryEmail, $l)) { - \OC::$server->getLogger()->logger("found in custom disposable domain list"); //throw new \Exception($l->t('The provided email domain is a disposable domain and cannot be used.')); throw new BlacklistedEmailException($l->t('The email address is disposable. Please provide another recovery address.')); }