Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add New Features #12

Merged
merged 1 commit into from Jul 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
115 changes: 83 additions & 32 deletions micropub.php
Expand Up @@ -5,7 +5,7 @@
Description: <a href="https://indiewebcamp.com/micropub">Micropub</a> server.
Author: Ryan Barrett
Author URI: https://snarfed.org/
Version: 0.3
Version: 0.4
*/

// Example command line for testing:
Expand All @@ -20,6 +20,23 @@
// curl -i -d 'code=CODE&me=SITE&client_id=indieauth&redirect_uri=https://indieauth.com/success' 'https://tokens.indieauth.com/token'
// 4. Extract the access_token parameter from the response body.

// For debugging purposes this will bypass Micropub authentication
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh. did you notice that it doesn't require auth when it's running on localhost? given that, do you think still we want this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually test on a remote server. A $1 a month VPS.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

// in favor of WordPress authentication
// Using this to test querying(q=) parameters quickly
if ( ! defined( 'MICROPUB_LOCAL_AUTH' ) )
define('MICROPUB_LOCAL_AUTH', '0');

// Allows for a custom Authentication and Token Endpoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, thanks!

if ( ! defined( 'MICROPUB_AUTHENTICATION_ENDPOINT' ) )
define('MICROPUB_AUTHENTICATION_ENDPOINT', 'https://indieauth.com/auth');
if ( ! defined( 'MICROPUB_TOKEN_ENDPOINT' ) )
define('MICROPUB_TOKEN_ENDPOINT', 'https://tokens.indieauth.com/token');

// For debugging purposes this will set all Micropub posts to Draft
if ( ! defined( 'MICROPUB_DRAFT_MODE' ) )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also a good idea!

define('MICROPUB_DRAFT_MODE', '0');


if (!class_exists('Micropub')) :

add_action('init', array('Micropub', 'init'));
Expand Down Expand Up @@ -70,14 +87,26 @@ public static function parse_query($wp) {
return;
}
header('Content-Type: text/plain; charset=' . get_option('blog_charset'));

$user_id = Micropub::authorize();
// For debug purposes be able to bypass Micropub auth with WordPress auth
if (MICROPUB_LOCAL_AUTH!=0) {
if (!is_user_logged_in()) {
auth_redirect();
}
$user_id = wp_get_current_user();
}
else {
$user_id = Micropub::authorize();
}
// TODO: future development note to add JSON support

// validate micropub request params
if (!isset($_POST['h']) && !isset($_POST['url'])) {
Micropub::error(400, 'requires either h= (for create) or url= (for update, delete, etc)');
if (!isset($_POST['h']) && !isset($_POST['url']) && !isset($_POST['edit-of']) && !isset($_GET['q'])) {
Micropub::error(400, 'Empty Micropub request. Either an "h", "edit-of", "url" or "q" property is required, e.g. h=entry or url=http://example.com/post/100 or q=syndicate-to');
}
if (isset($_GET['q'])) {
Micropub::return_query($user_id);
exit;
}

// support both action= and operation= parameter names
if (!isset($_POST['action'])) {
$_POST['action'] = isset($_POST['operation']) ? $_POST['operation']
Expand All @@ -89,11 +118,11 @@ public static function parse_query($wp) {
$args['post_author'] = $user_id;
}

if (!isset($_POST['url']) || $_POST['action'] == 'create') {
if (!isset($_POST['edit-of']) || !isset($_POST['url']) || $_POST['action'] == 'create') {
if ($user_id && !user_can($user_id, 'publish_posts')) {
Micropub::error(403, 'user id ' . $user_id . ' cannot publish posts');
}
$args['post_status'] = 'publish';
$args['post_status'] = MICROPUB_DRAFT_MODE ? 'draft' : 'publish';
kses_remove_filters(); // prevent sanitizing HTML tags in post_content
$args['ID'] = Micropub::check_error(wp_insert_post($args));
kses_init_filters();
Expand All @@ -103,7 +132,7 @@ public static function parse_query($wp) {

} else {
if ($args['ID'] == 0) {
Micropub::error(400, $_POST['url'] . ' not found');
Micropub::error(400, $_POST['edit-of'] ?: $_POST['url'] . ' not found');
}

if ($_POST['action'] == 'edit' || !isset($_POST['action'])) {
Expand Down Expand Up @@ -197,6 +226,24 @@ private static function authorize() {
return NULL;
}

private static function return_query($user_id) {
header('Content-type: application/x-www-form-urlencoded');
switch($_GET['q']) {
case 'syndicate-to':
// Fallback
case 'mp-syndicate-to':
status_header(200);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: these two lines will probably apply to all queries, not just syndicate-to, so consider moving them above the switch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the first line is the header line, what is the second? The 200 return wouldn't happen with an unsupported query string.

// return empty syndication target with filter
$syndication = apply_filters('micropub_syndicate-to', array(), $user_id);
if (!empty($syndication)) {
echo 'syndicate-to[]=' . implode('&syndicate-to[]=', $syndication);
}
break;
default:
Micropub::error(400, 'unknown query ' . $_GET['q']);
}
}

private static function handle_authorize_error($code, $msg) {
$home = untrailingslashit(home_url());
if ($home == 'http://localhost') {
Expand Down Expand Up @@ -226,10 +273,14 @@ private static function generate_args() {
}

// these are transformed or looked up
if (isset($_POST['edit-of'])) {
$args['ID'] = url_to_postid($_POST['edit-of']);
}
if (isset($_POST['url'])) {
$args['ID'] = url_to_postid($_POST['url']);
}


if (isset($_POST['published'])) {
$args['post_date'] = iso8601_to_datetime($_POST['published']);
$args['post_date_gmt'] = get_gmt_from_date($args['post_date']);
Expand All @@ -252,6 +303,9 @@ private static function generate_args() {
if (isset($_POST['content'])) {
$args['post_content'] = $_POST['content'];
}
else if (isset($_POST['summary'])) {
$args['post_content'] = $_POST['summary'];
}
}
// Else markup the content before passing it through
else {
Expand Down Expand Up @@ -377,24 +431,23 @@ private static function postprocess($post_id) {
* https://indiewebcamp.com/WordPress_Data#Microformats_data
*/
private static function store_mf2($post_id) {
$props = array('category', 'content', 'description', 'end', 'h', 'in-reply-to',
'like', 'like-of', 'location', 'name', 'photo', 'published',
'repost', 'repost-of', 'rsvp', 'slug', 'start', 'summary');

foreach ($props as $prop) {
if (isset($_POST[$prop])) {
$vals = $_POST[$prop];
if (!is_array($vals)) {
$vals = array($vals);
}

$key = 'mf2_' . $prop;
// Do not store access_token or other optional parameters
$blacklist = array('access_token');
foreach ($_POST as $key => $value) {
if (!is_array($value)) {
$value = array($value);
}
if (!in_array($key, $blacklist)) {
$key = 'mf2_' . $key;
delete_post_meta($post_id, $key); // clear old value(s)
foreach ($vals as $val) {
add_post_meta($post_id, $key, $val);
foreach ($value as $val) {
if (!empty($val)) {
add_post_meta($post_id, $key, $val);
}
}
}
}

}

private static function error($code, $msg) {
Expand All @@ -416,20 +469,18 @@ private static function check_error($result) {
* The micropub autodicovery meta tags
*/
public static function html_header() {
?>
<link rel="micropub" href="<?php echo site_url('?micropub=endpoint') ?>">
<link rel="authorization_endpoint" href="https://indieauth.com/auth">
<link rel="token_endpoint" href="https://tokens.indieauth.com/token">
<?php
echo '<link rel="micropub" href="' . site_url('?micropub=endpoint') . '">';
echo '<link rel="authorization_endpoint" href="' . MICROPUB_AUTHENTICATION_ENDPOINT . '">';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing $s?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nm, not needed since these are macros? or whatever they're called?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are constants.

echo '<link rel="token_endpoint" href="' . MICROPUB_TOKEN_ENDPOINT . '">';
}

/**
* The micropub autodicovery http-header
*/
public static function http_header() {
header('Link: <' . site_url('?micropub=endpoint') . '>; rel="micropub"', false);
header('Link: <https://indieauth.com/auth>; rel="authorization_endpoint"', false);
header('Link: <https://tokens.indieauth.com/token>; rel="token_endpoint"', false);
header('Link: <' . MICROPUB_AUTHENTICATION_ENDPOINT . '>; rel="authorization_endpoint"', false);
header('Link: <' . MICROPUB_TOKEN_ENDPOINT . '>; rel="token_endpoint"', false);
}

/**
Expand All @@ -439,9 +490,9 @@ public static function jrd_links($array) {
$array['links'][] = array('rel' => 'micropub',
'href' => site_url('?micropub=endpoint'));
$array['links'][] = array('rel' => 'authorization_endpoint',
'href' => 'https://indieauth.com/auth');
'href' => MICROPUB_AUTHENTICATION_ENDPOINT);
$array['links'][] = array('rel' => 'token_endpoint',
'href' => 'https://tokens.indieauth.com/token');
'href' => MICROPUB_TOKEN_ENDPOINT);
}
}

Expand Down
42 changes: 35 additions & 7 deletions readme.txt
@@ -1,8 +1,8 @@
=== Plugin Name ===
Contributors: snarfed
Contributors: snarfed, dshanske
Tags: micropub
Requires at least: 3.0.1
Tested up to: 4.1
Tested up to: 4.2
Stable tag: trunk
License: CC0
License URI: http://creativecommons.org/publicdomain/zero/1.0/
Expand Down Expand Up @@ -44,13 +44,18 @@ Micropub properties:
* `summary`
* `url`

Adds one WordPress filter, `before_micropub($wp_args)`, and one hook,
`after_micropub($post_id)`.
Adds the following filters:
* `before_micropub($wp_args)`
* `micropub_syndicate-to', array(), $user_id)`

And the hook:
* `after_micropub($post_id)`

Delegates token handling to
[tokens.indieauth.com](https://tokens.indieauth.com/). For ease of development,
if the WordPress site is running on `localhost`, it logs a warning if the access
token is missing or invalid and still allows the request.
[tokens.indieauth.com](https://tokens.indieauth.com/) by default. For ease of
development, if the WordPress site is running on `localhost`, it logs a warning
if the access token is missing or invalid and still allows the request.
There is also a wp-config option to use WordPress authentication.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please document the three new config options explicitly?


Stores [microformats2](http://microformats.org/wiki/microformats2) properties in
[post metadata](http://codex.wordpress.org/Function_Reference/post_meta_Function_Examples)
Expand All @@ -64,6 +69,18 @@ and pull requests are welcome!

Install from the WordPress plugin directory or put `micropub.php` in your plugin directory. No setup needed.

== Configuration Options ==

These configuration options can be enabled by adding them to your wp-config.php

* `define('MICROPUB_LOCAL_AUTH', '1')` - Bypasses Micropub authentication in
favor of WordPress authentication for testing purposes
* `define('MICROPUB_AUTHENTICATION_ENDPOINT'`, 'https://indieauth.com/auth')
Define a custom authentication endpoint
* `define('MICROPUB_TOKEN_ENDPOINT', 'https://tokens.indieauth.com/token')` -
Define a custom token endpoint
* `define('MICROPUB_DRAFT_MODE', '1')` - set all micropub posts to draft mode

== Frequently Asked Questions ==

None yet.
Expand All @@ -78,6 +95,17 @@ TODO

== Changelog ==

= 0.4 =
* Store all properties in post meta except those in a blacklist
* Support setting authentication and token endpoint in wp-config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please mention the config options' names explicitly here too

(set MICROPUB_AUTHENTICATION_ENDPOINT and MICROPUB_TOKEN_ENDPOINT)
* Support setting all micropub posts to draft in wp-config for testing by
setting MICROPUB_DRAFT_MODE in wp-config.
* Support using local auth to authenticate as opposed to Indieauth
as by setting MICROPUB_LOCAL_AUTH in wp-config
* Set content to summary if no content provided
* Support querying for syndicate-to and future query options

= 0.3 =
* Use the specific WordPress user whose URL matches the access token, if
possible.
Expand Down