diff --git a/.gitignore b/.gitignore index 6f849e8..37e2b9d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ vendor/ config.php config.test.php scripts/logs/ +php_errors.log +phpunit diff --git a/controllers/API.php b/controllers/API.php index 1a384dd..337283b 100644 --- a/controllers/API.php +++ b/controllers/API.php @@ -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(); diff --git a/lib/Telegraph/Webmention.php b/lib/Telegraph/Webmention.php index bf292af..4a37d38 100644 --- a/lib/Telegraph/Webmention.php +++ b/lib/Telegraph/Webmention.php @@ -99,7 +99,13 @@ class Webmention { $webmention->webmention_endpoint = $endpoint; $webmention->save(); - $response = $client->sendWebmentionToEndpoint($endpoint, $webmention->source, $webmention->target); + $params = []; + if($webmention->code) { + $params['code'] = $webmention->code; + if($webmention->realm) + $params['realm'] = $webmention->realm; + } + $response = $client->sendWebmentionToEndpoint($endpoint, $webmention->source, $webmention->target, $params); if(in_array($response['code'], [200,201,202])) { $status = 'accepted'; diff --git a/migrations/20160929174900.sql b/migrations/20160929174900.sql new file mode 100644 index 0000000..9627a77 --- /dev/null +++ b/migrations/20160929174900.sql @@ -0,0 +1,3 @@ +ALTER TABLE webmentions +ADD COLUMN `code` TEXT DEFAULT NULL AFTER `vouch`, +ADD COLUMN `realm` TEXT DEFAULT NULL AFTER `code`; diff --git a/migrations/init.sql b/migrations/init.sql index ccbdf09..171eab4 100644 --- a/migrations/init.sql +++ b/migrations/init.sql @@ -10,6 +10,7 @@ CREATE TABLE `roles` ( CREATE TABLE `sites` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, + `url` VARCHAR(255) DEFAULT NULL, `created_by` int(10) unsigned DEFAULT NULL, `created_at` datetime DEFAULT NULL, PRIMARY KEY (`id`) @@ -46,6 +47,8 @@ CREATE TABLE `webmentions` ( `source` varchar(255) DEFAULT NULL, `target` varchar(255) DEFAULT NULL, `vouch` varchar(255) DEFAULT NULL, + `code` text DEFAULT NULL, + `realm` text DEFAULT NULL, `callback` varchar(255) DEFAULT NULL, `webmention_endpoint` varchar(255) DEFAULT NULL, `webmention_status_url` varchar(255) DEFAULT NULL, diff --git a/public/assets/styles.css b/public/assets/styles.css index 7913bc4..209c08c 100644 --- a/public/assets/styles.css +++ b/public/assets/styles.css @@ -42,4 +42,8 @@ h2.site-name:hover .edit-site { -webkit-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.5); -moz-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.5); box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.5); +} + +table.logs pre { + white-space: normal; } \ No newline at end of file diff --git a/views/api.php b/views/api.php index 47a4410..4662906 100644 --- a/views/api.php +++ b/views/api.php @@ -11,16 +11,22 @@ $this->layout('layout-loggedin', ['title' => $title, 'accounts' => $accounts, 'u

Send a webmention to a specific page

Post to `https://telegraph.p3k.io/webmention` +### Required * `token` - your API key obtained after signing up * `source` - the URL of your post * `target` OR `target_domain` - the URL or domain you linked to, respectively -* `callback` - (optional) - a URL that will receive a web hook when new information about this webmention is available + +### Optional +* `callback` - a URL that will receive a web hook when new information about this webmention is available +* `vouch` - see Vouch +* `code` - see Private Webmention +* `realm` - see Private Webmention The Telegraph API will validate the parameters and then queue the webmention for sending. If there was a problem with the request, you will get an error response immediately. -The API will first make an HTTP request to the source URL, and look for a link to the target on the page. This happens synchronously so you will get this error reply immediately. +The API will first make an HTTP request to the source URL, and look for a link to the target on the page. This happens synchronously so you will get this error reply immediately. (Note that this verification is not performed for sending private Webmentions.) -If you pass `target_domain` instead of `target`, Telegraph will find and enqueue webmentions for all links to that domain. +If you pass `target_domain` instead of `target`, Telegraph will find and enqueue webmentions for all links to that domain. However, sending a private Webmention requires that you send `target` rather than `target_domain`. #### Errors * `authentication_required` - the token parameter was missing diff --git a/views/webmention-details.php b/views/webmention-details.php index d68a3bd..7ebab0c 100644 --- a/views/webmention-details.php +++ b/views/webmention-details.php @@ -30,6 +30,18 @@ e($webmention->vouch) ?> + code): ?> + + Code + e($webmention->code) ?> + + + realm): ?> + + Realm + e($webmention->realm) ?> + + callback): ?> Callback URL @@ -48,13 +60,13 @@ webmention_endpoint): ?> Webmention Endpoint - e($webmention->webmention_endpoint) ?> + e($webmention->webmention_endpoint) ?> pingback_endpoint): ?> Pingback Endpoint - e($webmention->pingback_endpoint) ?> + e($webmention->pingback_endpoint) ?> webmention_endpoint == false && $webmention->pingback_endpoint == false): ?> @@ -66,14 +78,20 @@ webmention_endpoint): ?> Status URL - webmention_status_url ? $this->e($webmention->webmention_status_url) : 'The webmention endpoint did not return a status URL' ?> + + webmention_status_url): ?> + e($webmention->webmention_status_url) ?> + + The webmention endpoint did not return a status URL + +

Logs

- +
Date