mirror of
https://github.com/anikeen-com/yaac.git
synced 2026-03-13 13:46:10 +00:00
added dns support
This commit is contained in:
@@ -267,6 +267,8 @@ class Client
|
||||
{
|
||||
if ($type == self::VALIDATION_HTTP) {
|
||||
return $this->selfHttpTest($authorization, $maxAttempts);
|
||||
} elseif ($type == self::VALIDATION_DNS) {
|
||||
return $this->selfDNSTest($authorization, $maxAttempts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,21 +396,17 @@ class Client
|
||||
*/
|
||||
protected function selfHttpTest(Authorization $authorization, $maxAttempts)
|
||||
{
|
||||
$file = $authorization->getFile();
|
||||
$authorization->getDomain();
|
||||
do {
|
||||
$maxAttempts--;
|
||||
|
||||
try {
|
||||
$response = $this->getSelfTestClient()->request(
|
||||
'GET',
|
||||
'http://' . $authorization->getDomain() . '/.well-known/acme-challenge/' . $file->getFilename()
|
||||
'http://' . $authorization->getDomain() . '/.well-known/acme-challenge/' .
|
||||
$authorization->getFile()->getFilename()
|
||||
);
|
||||
$contents = (string)$response->getBody();
|
||||
if ($contents == $file->getContents()) {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ($contents == $authorization->getFile()->getContents()) {
|
||||
return true;
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
}
|
||||
@@ -417,6 +415,54 @@ class Client
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Self DNS test client that uses Cloudflare's DNS API
|
||||
* @param Authorization $authorization
|
||||
* @param $maxAttempts
|
||||
* @return bool
|
||||
*/
|
||||
protected function selfDNSTest(Authorization $authorization, $maxAttempts)
|
||||
{
|
||||
do {
|
||||
$response = $this->getSelfTestDNSClient()->get(
|
||||
'/dns-query',
|
||||
[
|
||||
'query' => [
|
||||
'name' => $authorization->getTxtRecord()->getName(),
|
||||
'type' => 'TXT'
|
||||
]
|
||||
]
|
||||
);
|
||||
$data = json_decode((string)$response->getBody(), true);
|
||||
if (isset($data['Answer'])) {
|
||||
foreach ($data['Answer'] as $result) {
|
||||
if (trim($result['data'], "\"") == $authorization->getTxtRecord()->getValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep(ceil(30 / $maxAttempts));
|
||||
$maxAttempts--;
|
||||
} while ($maxAttempts > 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the preconfigured client to call Cloudflare's DNS API
|
||||
* @return HttpClient
|
||||
*/
|
||||
protected function getSelfTestDNSClient()
|
||||
{
|
||||
return new HttpClient([
|
||||
'base_uri' => 'https://cloudflare-dns.com',
|
||||
'connect_timeout' => 10,
|
||||
'headers' => [
|
||||
'Accept' => 'application/dns-json',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the client
|
||||
*/
|
||||
|
||||
@@ -122,13 +122,20 @@ class Authorization
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DNS record object
|
||||
*
|
||||
* @param Challenge $challenge
|
||||
* @return string containing TXT record for DNS challenge
|
||||
* @return Record|bool
|
||||
*/
|
||||
public function getTxtRecord(Challenge $challenge)
|
||||
public function getTxtRecord()
|
||||
{
|
||||
$raw=$challenge->getToken() . '.' . $this->digest;
|
||||
$hash=hash('sha256', $raw, true);
|
||||
return Helper::toSafeString($hash);
|
||||
$challenge = $this->getDnsChallenge();
|
||||
if ($challenge !== false) {
|
||||
$hash = hash('sha256', $challenge->getToken() . '.' . $this->digest, true);
|
||||
$value = Helper::toSafeString($hash);
|
||||
return new Record('_acme-challenge.' . $this->getDomain(), $value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
46
src/Data/Record.php
Normal file
46
src/Data/Record.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Afosto\Acme\Data;
|
||||
|
||||
class Record
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Record constructor.
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct(string $name, string $value)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DNS TXT record name for validation
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the record value for DNS validation
|
||||
* @return string
|
||||
*/
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -92,11 +92,11 @@ class Helper
|
||||
file_put_contents($fn, implode("\n", $config));
|
||||
$csr = openssl_csr_new([
|
||||
'countryName' => 'NL',
|
||||
'commonName' => $primaryDomain,
|
||||
'commonName' => $primaryDomain,
|
||||
], $key, [
|
||||
'config' => $fn,
|
||||
'config' => $fn,
|
||||
'req_extensions' => 'SAN',
|
||||
'digest_alg' => 'sha512',
|
||||
'digest_alg' => 'sha512',
|
||||
]);
|
||||
unlink($fn);
|
||||
|
||||
@@ -140,37 +140,4 @@ class Helper
|
||||
|
||||
return $accountDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until a set of DNS records return specific TXT record values
|
||||
*
|
||||
* @param array mapping domain to desired TXT record value
|
||||
* @param $txtRecord
|
||||
* @param int $maxSeconds to wait
|
||||
* @return bool true if record found, false otherwise
|
||||
*/
|
||||
public static function waitForDNS(array $records, $maxSeconds=60)
|
||||
{
|
||||
$waitUntil = time() + $maxSeconds;
|
||||
|
||||
do {
|
||||
//validate all remaining records..
|
||||
foreach($records as $domain=>$txtRecord) {
|
||||
$record=dns_get_record($domain, DNS_TXT);
|
||||
if (isset($record[0]['txt']) && ($record[0]['txt']===$txtRecord)) {
|
||||
unset($records[$domain]);
|
||||
}
|
||||
}
|
||||
|
||||
//did we find them all?
|
||||
if (empty($records)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//otherwise still domains to check...have a short sleep
|
||||
sleep(1);
|
||||
} while(time() < $waitUntil);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user