diff --git a/webmention.php b/webmention.php
index f7854dc0..9deb0eed 100755
--- a/webmention.php
+++ b/webmention.php
@@ -69,6 +69,39 @@ public static function query_var($vars) {
return $vars;
}
+ /**
+ * generate a valid expire code.
+ * Three possible values are valid at any one time, ticks: 0, 1, or 2
+ *
+ * @return array
+ */
+ public static function expire_code( $tick = 0 ) {
+ $action = 'web mention endpoint';
+ $time_format = 'Y-m-d a';
+ $time_block = 12 * HOUR_IN_SECONDS;
+ $tick = abs( intval( $tick ) );
+ if ( 3 < $tick ) {
+ // something wrong, tick too high/
+ // use default
+ $tick = 0;
+ }
+ $expire_code = date( $time_format, time() - ( $tick * $time_block ) );
+
+ // always use logged out user code, endpoint may be looked up by a logged in user
+ // while the web mention comes from a logged out user (using curl or similar)
+ $uid = 0;
+
+ // as above, always use the lgoged out token.
+ $token = '';
+
+ // custom hash used rather than standard nonce to prevent session data polluting the
+ // web mention endpoint. The endpoint needs to remain the same for all users.
+ $expire_code = wp_hash( $expire_code . '|' . $action . '|' . $uid . '|' . $token, 'nonce' );
+
+ return $expire_code;
+ }
+
+
/**
* Parse the WebMention request and render the document
*
@@ -81,13 +114,34 @@ public static function parse_query($wp) {
if (!array_key_exists('webmention', $wp->query_vars)) {
return;
}
-
- $content = file_get_contents('php://input');
- parse_str($content);
+ else {
+ // check if the end point has expired
+ $valid_ticks = array( 0, -1, -2 );
+
+ $supplied_code = get_query_var( 'webmention' );
+ $is_valid = false;
+
+ foreach ( $valid_ticks as $tick ) {
+ if ( hash_equals( WebMentionPlugin::expire_code( $tick ), $supplied_code ) ) {
+ $is_valid = true;
+ break;
+ }
+ }
+ }
// plain text header
header('Content-Type: text/plain; charset=' . get_option('blog_charset'));
+ // fail if invalide endpoint
+ if ( false == $is_valid ) {
+ status_header(403);
+ echo "invalid endpoint";
+ exit;
+ }
+
+ $content = file_get_contents('php://input');
+ parse_str($content);
+
// check if source url is transmitted
if (!isset($source)) {
status_header(400);
@@ -556,8 +610,9 @@ public static function discover_endpoint($url) {
*/
public static function html_header() {
// backwards compatibility with v0.1
- echo ''."\n";
- echo ''."\n";
+ $endpoint_code = WebMentionPlugin::expire_code();
+ echo ''."\n";
+ echo ''."\n";
}
/**
@@ -565,8 +620,9 @@ public static function html_header() {
*/
public static function http_header() {
// backwards compatibility with v0.1
- header('Link: <'.site_url("?webmention=endpoint").'>; rel="http://webmention.org/"', false);
- header('Link: <'.site_url("?webmention=endpoint").'>; rel="webmention"', false);
+ $endpoint_code = WebMentionPlugin::expire_code();
+ header('Link: <'.site_url("?webmention=" . $endpoint_code).'>; rel="http://webmention.org/"', false);
+ header('Link: <'.site_url("?webmention=" . $endpoint_code).'>; rel="webmention"', false);
}
/**