Browse Source

add `code` and `realm` parameters for sending private webmentions

main
Aaron Parecki 4 years ago
parent
commit
243c9c7802
No known key found for this signature in database GPG Key ID: 3745E500B4FF7CB1
8 changed files with 97 additions and 41 deletions
  1. +2
    -0
      .gitignore
  2. +47
    -33
      controllers/API.php
  3. +7
    -1
      lib/Telegraph/Webmention.php
  4. +3
    -0
      migrations/20160929174900.sql
  5. +3
    -0
      migrations/init.sql
  6. +4
    -0
      public/assets/styles.css
  7. +9
    -3
      views/api.php
  8. +22
    -4
      views/webmention-details.php

+ 2
- 0
.gitignore View File

@ -3,3 +3,5 @@ vendor/
config.php
config.test.php
scripts/logs/
php_errors.log
phpunit

+ 47
- 33
controllers/API.php View File

@ -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();

+ 7
- 1
lib/Telegraph/Webmention.php View File

@ -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';

+ 3
- 0
migrations/20160929174900.sql View File

@ -0,0 +1,3 @@
ALTER TABLE webmentions
ADD COLUMN `code` TEXT DEFAULT NULL AFTER `vouch`,
ADD COLUMN `realm` TEXT DEFAULT NULL AFTER `code`;

+ 3
- 0
migrations/init.sql View File

@ -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,

+ 4
- 0
public/assets/styles.css View File

@ -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;
}

+ 9
- 3
views/api.php View File

@ -11,16 +11,22 @@ $this->layout('layout-loggedin', ['title' => $title, 'accounts' => $accounts, 'u
<h2 class="ui dividing header" id="send">Send a webmention to a specific page</h2>
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 <a href="https://indieweb.org/Vouch">Vouch</a>
* `code` - see <a href="https://indieweb.org/Private-Webmention">Private Webmention</a>
* `realm` - see <a href="https://indieweb.org/Private-Webmention">Private Webmention</a>
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

+ 22
- 4
views/webmention-details.php View File

@ -30,6 +30,18 @@
<td class="right"><a href="<?= $this->e($webmention->vouch) ?>"><?= $this->e($webmention->vouch) ?></a></td>
</tr>
<? endif; ?>
<? if($webmention->code): ?>
<tr>
<td class="left"><b>Code</b></td>
<td class="right"><code><?= $this->e($webmention->code) ?></code></td>
</tr>
<? endif; ?>
<? if($webmention->realm): ?>
<tr>
<td class="left"><b>Realm</b></td>
<td class="right"><code><?= $this->e($webmention->realm) ?></code></td>
</tr>
<? endif; ?>
<? if($webmention->callback): ?>
<tr>
<td class="left"><b>Callback URL</b></td>
@ -48,13 +60,13 @@
<? if($webmention->webmention_endpoint): ?>
<tr>
<td><b>Webmention Endpoint</b></td>
<td><?= $this->e($webmention->webmention_endpoint) ?></td>
<td><a href="<?= $this->e($webmention->webmention_endpoint) ?>"><?= $this->e($webmention->webmention_endpoint) ?></a></td>
</tr>
<? endif; ?>
<? if($webmention->pingback_endpoint): ?>
<tr>
<td><b>Pingback Endpoint</b></td>
<td><?= $this->e($webmention->pingback_endpoint) ?></td>
<td><a href="<?= $this->e($webmention->pingback_endpoint) ?>"><?= $this->e($webmention->pingback_endpoint) ?></a></td>
</tr>
<? endif; ?>
<? if($webmention->webmention_endpoint == false && $webmention->pingback_endpoint == false): ?>
@ -66,14 +78,20 @@
<? if($webmention->webmention_endpoint): ?>
<tr>
<td><b>Status URL</b></td>
<td><?= $webmention->webmention_status_url ? $this->e($webmention->webmention_status_url) : 'The webmention endpoint did not return a status URL' ?></td>
<td>
<? if($webmention->webmention_status_url): ?>
<a href="<?= $this->e($webmention->webmention_status_url) ?>"><?= $this->e($webmention->webmention_status_url) ?></a>
<? else: ?>
The webmention endpoint did not return a status URL
<? endif; ?>
</td>
</tr>
<? endif; ?>
</tbody></table>
<h2>Logs</h2>
<table class="ui very compact table">
<table class="ui very compact table logs">
<thead>
<tr>
<th>Date</th>

Loading…
Cancel
Save