|
|
@ -107,50 +107,62 @@ class API { |
|
|
|
]); |
|
|
|
} |
|
|
|
|
|
|
|
# If there is no code given,
|
|
|
|
# Synchronously check the source URL and verify that it actually contains
|
|
|
|
# a link to the target. This way we prevent this API from sending known invalid mentions.
|
|
|
|
$sourceData = $this->http->get($source); |
|
|
|
if($request->get('code')) { |
|
|
|
# target URL is required
|
|
|
|
if(!$target) { |
|
|
|
return $this->respond($response, 400, [ |
|
|
|
'error' => 'not_supported', |
|
|
|
'error_description' => 'The target_domain parameter is not supported for sending private webmentions' |
|
|
|
]); |
|
|
|
} |
|
|
|
|
|
|
|
$doc = new DOMDocument(); |
|
|
|
libxml_use_internal_errors(true); # suppress parse errors and warnings
|
|
|
|
@$doc->loadHTML(self::toHtmlEntities($sourceData['body']), LIBXML_NOWARNING|LIBXML_NOERROR); |
|
|
|
libxml_clear_errors(); |
|
|
|
$found[$target] = null; |
|
|
|
} else { |
|
|
|
$sourceData = $this->http->get($source); |
|
|
|
|
|
|
|
if(!$doc) { |
|
|
|
return $this->respond($response, 400, [ |
|
|
|
'error' => 'source_not_html', |
|
|
|
'error_description' => 'The source document could not be parsed as HTML' |
|
|
|
]); |
|
|
|
} |
|
|
|
$doc = new DOMDocument(); |
|
|
|
libxml_use_internal_errors(true); # suppress parse errors and warnings
|
|
|
|
@$doc->loadHTML(self::toHtmlEntities($sourceData['body']), LIBXML_NOWARNING|LIBXML_NOERROR); |
|
|
|
libxml_clear_errors(); |
|
|
|
|
|
|
|
$xpath = new DOMXPath($doc); |
|
|
|
if(!$doc) { |
|
|
|
return $this->respond($response, 400, [ |
|
|
|
'error' => 'source_not_html', |
|
|
|
'error_description' => 'The source document could not be parsed as HTML' |
|
|
|
]); |
|
|
|
} |
|
|
|
|
|
|
|
$found = []; |
|
|
|
foreach($xpath->query('//a[@href]') as $href) { |
|
|
|
$url = $href->getAttribute('href'); |
|
|
|
if($target) { |
|
|
|
# target parameter was provided
|
|
|
|
if($url == $target) { |
|
|
|
$found[$url] = null; |
|
|
|
} |
|
|
|
} elseif($target_domain) { |
|
|
|
# target_domain parameter was provided
|
|
|
|
$domain = parse_url($url, PHP_URL_HOST); |
|
|
|
if($domain && ($domain == $target_domain || str_ends_with($domain, '.' . $target_domain))) { |
|
|
|
$found[$url] = null; |
|
|
|
$xpath = new DOMXPath($doc); |
|
|
|
|
|
|
|
$found = []; |
|
|
|
foreach($xpath->query('//a[@href]') as $href) { |
|
|
|
$url = $href->getAttribute('href'); |
|
|
|
if($target) { |
|
|
|
# target parameter was provided
|
|
|
|
if($url == $target) { |
|
|
|
$found[$url] = null; |
|
|
|
} |
|
|
|
} elseif($target_domain) { |
|
|
|
# target_domain parameter was provided
|
|
|
|
$domain = parse_url($url, PHP_URL_HOST); |
|
|
|
if($domain && ($domain == $target_domain || str_ends_with($domain, '.' . $target_domain))) { |
|
|
|
$found[$url] = null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(!$found) { |
|
|
|
return $this->respond($response, 400, [ |
|
|
|
'error' => 'no_link_found', |
|
|
|
'error_description' => 'The source document does not have a link to the target URL or domain' |
|
|
|
]); |
|
|
|
if(!$found) { |
|
|
|
return $this->respond($response, 400, [ |
|
|
|
'error' => 'no_link_found', |
|
|
|
'error_description' => 'The source document does not have a link to the target URL or domain' |
|
|
|
]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
# Everything checked out, so write the webmention to the log and queue a job to start sending
|
|
|
|
# TODO: database transaction?
|
|
|
|
# Write the webmention to the database and queue a job to start sending
|
|
|
|
|
|
|
|
$statusURLs = []; |
|
|
|
foreach($found as $url=>$_) { |
|
|
@ -162,6 +174,8 @@ class API { |
|
|
|
$w->source = $source; |
|
|
|
$w->target = $url; |
|
|
|
$w->vouch = $request->get('vouch'); |
|
|
|
$w->code = $request->get('code'); |
|
|
|
$w->realm = $request->get('realm'); |
|
|
|
$w->callback = $callback; |
|
|
|
$w->save(); |
|
|
|
|
|
|
|