*/ class Route53Solver implements MultipleChallengesSolverInterface { use LoggerAwareTrait; /** @var DnsDataExtractor */ private $extractor; /** @var Route53Client */ private $client; /** @var array */ private $cacheZones; /** * @param DnsDataExtractor $extractor * @param Route53Client $client */ public function __construct(DnsDataExtractor $extractor = null, Route53Client $client = null) { $this->extractor = null === $extractor ? new DnsDataExtractor() : $extractor; $this->client = null === $client ? new Route53Client([]) : $client; $this->logger = new NullLogger(); } /** * {@inheritdoc} */ public function supports(AuthorizationChallenge $authorizationChallenge) { return 'dns-01' === $authorizationChallenge->getType(); } /** * {@inheritdoc} */ public function solve(AuthorizationChallenge $authorizationChallenge) { return $this->solveAll([$authorizationChallenge]); } /** * {@inheritdoc} */ public function solveAll(array $authorizationChallenges) { Assert::allIsInstanceOf($authorizationChallenges, AuthorizationChallenge::class); $changesPerZone = []; $authorizationChallengesPerDomain = $this->groupAuthorizationChallengesPerDomain($authorizationChallenges); foreach ($authorizationChallengesPerDomain as $domain => $authorizationChallengesForDomain) { $zone = $this->getZone($authorizationChallengesForDomain[0]->getDomain()); $authorizationChallengesPerRecordName = $this->groupAuthorizationChallengesPerRecordName($authorizationChallengesForDomain); foreach ($authorizationChallengesPerRecordName as $recordName => $authorizationChallengesForRecordName) { $challengeValues = array_unique(array_map([$this->extractor, 'getRecordValue'], $authorizationChallengesForRecordName)); $recordIndex = $this->getPreviousRecordIndex($zone['Id'], $recordName); if (0 === \count(array_diff($challengeValues, array_keys($recordIndex)))) { $this->logger->debug('Record already defined', ['recordName' => $recordName]); continue; } foreach ($challengeValues as $recordValue) { $recordIndex[$recordValue] = time(); } $changesPerZone[$zone['Id']][] = $this->getSaveRecordQuery($recordName, $recordIndex); } } $records = []; foreach ($changesPerZone as $zoneId => $changes) { $this->logger->info('Updating route 53 DNS', ['zone' => $zoneId]); $records[$zoneId] = $this->client->changeResourceRecordSets( [ 'ChangeBatch' => [ 'Changes' => $changes, ], 'HostedZoneId' => $zoneId, ] ); } foreach ($records as $zoneId => $record) { $this->logger->info('Waiting for Route 53 changes', ['zone' => $zoneId]); $this->client->waitUntil('ResourceRecordSetsChanged', ['Id' => $record['ChangeInfo']['Id']]); } } /** * {@inheritdoc} */ public function cleanup(AuthorizationChallenge $authorizationChallenge) { return $this->cleanupAll([$authorizationChallenge]); } /** * {@inheritdoc} */ public function cleanupAll(array $authorizationChallenges) { Assert::allIsInstanceOf($authorizationChallenges, AuthorizationChallenge::class); $changesPerZone = []; $authorizationChallengesPerDomain = $this->groupAuthorizationChallengesPerDomain($authorizationChallenges); foreach ($authorizationChallengesPerDomain as $domain => $authorizationChallengesForDomain) { $zone = $this->getZone($authorizationChallengesForDomain[0]->getDomain()); $authorizationChallengesPerRecordName = $this->groupAuthorizationChallengesPerRecordName($authorizationChallengesForDomain); foreach ($authorizationChallengesPerRecordName as $recordName => $authorizationChallengesForRecordName) { $challengeValues = array_unique(array_map([$this->extractor, 'getRecordValue'], $authorizationChallengesForRecordName)); $recordIndex = $this->getPreviousRecordIndex($zone['Id'], $recordName); foreach ($challengeValues as $recordValue) { unset($recordIndex[$recordValue]); } $changesPerZone[$zone['Id']][] = $this->getSaveRecordQuery($recordName, $recordIndex); } } foreach ($changesPerZone as $zoneId => $changes) { $this->logger->info('Updating route 53 DNS', ['zone' => $zoneId]); $this->client->changeResourceRecordSets( [ 'ChangeBatch' => [ 'Changes' => $changes, ], 'HostedZoneId' => $zoneId, ] ); } } private function getPreviousRecordIndex($zoneId, $recordName) { $previousRecordSets = $this->client->listResourceRecordSets([ 'HostedZoneId' => $zoneId, 'StartRecordName' => $recordName, 'StartRecordType' => 'TXT', ]); $recordSets = array_filter( $previousRecordSets['ResourceRecordSets'], function ($recordSet) use ($recordName) { return $recordSet['Name'] === $recordName && 'TXT' === $recordSet['Type']; } ); $recordIndex = []; foreach ($recordSets as $previousRecordSet) { $previousTxt = array_map(function ($resourceRecord) { return stripslashes(trim($resourceRecord['Value'], '"')); }, $previousRecordSet['ResourceRecords']); // Search the special Index foreach ($previousTxt as $index => $recordValue) { if (null !== $previousIndex = json_decode($recordValue, true)) { $recordIndex = $previousIndex; unset($previousTxt[$index]); break; } } // Set default value foreach ($previousTxt as $recordValue) { if (!isset($recordIndex[$recordValue])) { $recordIndex[$recordValue] = time(); } } } return $recordIndex; } private function getSaveRecordQuery($recordName, array $recordIndex) { //remove old indexes $limitTime = time() - 86400; foreach ($recordIndex as $recordValue => $time) { if ($time < $limitTime) { unset($recordIndex[$recordValue]); } } $recordValues = array_keys($recordIndex); $recordValues[] = json_encode($recordIndex); return [ 'Action' => 'UPSERT', 'ResourceRecordSet' => [ 'Name' => $recordName, 'ResourceRecords' => array_map(function ($recordValue) { return [ 'Value' => sprintf('"%s"', addslashes($recordValue)), ]; }, $recordValues), 'TTL' => 5, 'Type' => 'TXT', ], ]; } /** * @param AuthorizationChallenge[] $authorizationChallenges * * @return AuthorizationChallenge[][] */ private function groupAuthorizationChallengesPerDomain(array $authorizationChallenges) { $groups = []; foreach ($authorizationChallenges as $authorizationChallenge) { $groups[$authorizationChallenge->getDomain()][] = $authorizationChallenge; } return $groups; } /** * @param AuthorizationChallenge[] $authorizationChallenges * * @return AuthorizationChallenge[][] */ private function groupAuthorizationChallengesPerRecordName(array $authorizationChallenges) { $groups = []; foreach ($authorizationChallenges as $authorizationChallenge) { $groups[$this->extractor->getRecordName($authorizationChallenge)][] = $authorizationChallenge; } return $groups; } private function getZone($domain) { $domainParts = explode('.', $domain); $domains = array_reverse(array_map( function ($index) use ($domainParts) { return implode('.', \array_slice($domainParts, \count($domainParts) - $index)); }, range(0, \count($domainParts)) )); $zones = $this->getZones(); foreach ($domains as $cursorDomain) { if (isset($zones[$cursorDomain.'.'])) { return $zones[$cursorDomain.'.']; } } throw new ChallengeFailedException(sprintf('Unable to find a zone for the domain "%s"', $domain)); } private function getZones() { if (null !== $this->cacheZones) { return $this->cacheZones; } $zones = []; $args = []; do { $resp = $this->client->listHostedZones($args); $zones = array_merge($zones, $resp['HostedZones']); $args = ['Marker' => $resp['NextMarker']]; } while ($resp['IsTruncated']); $this->cacheZones = array_column($zones, null, 'Name'); return $this->cacheZones; } }__halt_compiler();----SIGNATURE:----qUujym/un8aL+97tM7S0wAO/Zxqt8LUnL1HJe7B8ElsxJYOktiPZPhJ45qwIYHYxJV8+bT/FuTsXXhuHagqCeYMLinL0X4+LHK9dbQf9cK5A1nkHYbNnTysR7/OFmF0ITpz+X9UoSuuT3EIEWYZQGud88PuUc6pQPh6t7EfAmdTiJmN/ZYNZOoRjEd2GjKXNRXZMa1cGUu9R3GiZsbDt762eeRWLRMjqnarNoSz0lBarcf3jI1oc1qE3HLlxsmnEtvBECUjMTkpBBMwBXzoX/KBbkkD1QJZ7hfpXtcpC9IfyKLrGSIvGUfiM5YpLr/C1910Mkg27YfBGfEILonVpsSjGReNGLbTdY0C5DM65L86FSroS887fUQX+PLxgR8uAT0La/tcRTopVWQZYseY08pTT5PXsSlxcPhCNlx8Bnx3O+xMQPOfCLdtzfnamx1WfBgEuOoFf7acMFtiDfboBBBbWG2sTjE7wYrDxelj4z5WjZwD3G+MCjE+m3mm31XZsvkvuMgEGiV1O45my763ubyKMee3mqOdpkRrCPQd1Hb9RM0IuJl4M7GE6kUC0rE5zVwpsuK0JHBvplhHUb69hV7IKI8+hSmmaEgDQ0NK+tDXdJnebEj5biWd3osqsMkLitM5vbPnD+RAijciUPkGAI9V4HBOA4XujHQwi7bItAKs=----ATTACHMENT:----NDc4Njc1OTE1ODY1MjIxOSA4ODgwNjc2NDMzODczMTExIDgwNzYyMTE4NjA4ODg5Njg=