'name' => '',
'imageurl' => '',
);
- $userbaseurl = Urls::full('/user/');
- if (substr($me, 0, strlen($userbaseurl)) == $userbaseurl) {
- //actual user URL - loads his data
- $userid = substr($me, strrpos($me, '/') + 1, -4);
- if (intval($userid) == $userid) {
- $storage = new Storage();
- $rowUser = $storage->getUser($userid);
- if ($rowUser !== null) {
- $id['mode'] = 'data';
- $id['name'] = $rowUser->user_name;
- $id['imageurl'] = $rowUser->user_imageurl;
- if ($id['imageurl'] == Urls::userImg()) {
- $id['imageurl'] = '';
- }
+ $userId = Urls::userId($me);
+ if ($userId !== null) {
+ $storage = new Storage();
+ $rowUser = $storage->getUser($userId);
+ if ($rowUser !== null) {
+ $id['mode'] = 'data';
+ $id['name'] = $rowUser->user_name;
+ $id['imageurl'] = $rowUser->user_imageurl;
+ if ($id['imageurl'] == Urls::userImg()) {
+ $id['imageurl'] = '';
}
}
}
require 'www-header.php';
/**
- * Send out an error
+ * Send out a micropub error
*
* @param string $status HTTP status code line
* @param string $code One of the allowed status types:
* - not_found
* @param string $description
*/
-function error($status, $code, $description)
+function mpError($status, $code, $description)
{
header($status);
header('Content-Type: application/json');
exit(1);
}
-function handleCreate($json)
+function validateToken($token)
{
+ $ctx = stream_context_create(
+ array(
+ 'http' => array(
+ 'header' => array(
+ 'Authorization: Bearer ' . $token
+ ),
+ ),
+ )
+ );
+ //FIXME: make hard-coded token server URL configurable
+ $res = @file_get_contents(Urls::full('/token.php'), false, $ctx);
+ list($dummy, $code, $msg) = explode(' ', $http_response_header[0]);
+ if ($code != 200) {
+ mpError(
+ 'HTTP/1.0 403 Forbidden',
+ 'forbidden',
+ 'Error verifying bearer token'
+ );
+ }
+
+ parse_str($res, $data);
+ //FIXME: they spit out non-micropub json error responess
+ verifyUrlParameter($data, 'me');
+ verifyUrlParameter($data, 'client_id');
+ verifyParameter($data, 'scope');
+
+ return [$data['me'], $data['client_id'], $data['scope']];
+}
+
+function handleCreate($json, $token)
+{
+ list($me, $client_id, $scope) = validateToken($token);
+ $userId = Urls::userId($me);
+ if ($userId === null) {
+ mpError(
+ 'HTTP/1.0 403 Forbidden',
+ 'forbidden',
+ 'Invalid user URL'
+ );
+ }
+ $storage = new Storage();
+ $rowUser = $storage->getUser($userId);
+ if ($rowUser === null) {
+ mpError(
+ 'HTTP/1.0 403 Forbidden',
+ 'forbidden',
+ 'User not found: ' . $userId
+ );
+ }
+
if (!isset($json->properties->{'in-reply-to'})) {
- error(
+ mpError(
'HTTP/1.0 400 Bad Request',
'invalid_request',
'Only replies accepted'
);
}
- //FIXME: read bearer token
- //FIXME: get user ID
+
$storage = new Storage();
try {
- $id = $storage->addComment($json, 0);
+ $id = $storage->addComment($json, $userId);
header('HTTP/1.0 201 Created');
header('Location: ' . Urls::full(Urls::comment($id)));
}
}
+function getTokenFromHeader()
+{
+ if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
+ mpError(
+ 'HTTP/1.0 403 Forbidden', 'forbidden',
+ 'Authorization HTTP header missing'
+ );
+ }
+ list($bearer, $token) = explode(' ', $_SERVER['HTTP_AUTHORIZATION'], 2);
+ if ($bearer !== 'Bearer') {
+ mpError(
+ 'HTTP/1.0 403 Forbidden', 'forbidden',
+ 'Authorization header must start with "Bearer"'
+ );
+ }
+ return trim($token);
+}
+
+
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (!isset($_GET['q'])) {
- error(
+ mpError(
'HTTP/1.1 400 Bad Request',
'invalid_request',
'Parameter "q" missing.'
}
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (!isset($_SERVER['CONTENT_TYPE'])) {
- error(
+ mpError(
'HTTP/1.1 400 Bad Request',
'invalid_request',
'Content-Type header missing.'
$base->type = ['h-' . $data['h']];
unset($data['h']);
}
+ if (isset($data['access_token'])) {
+ $token = $data['access_token'];
+ unset($data['access_token']);
+ } else {
+ $token = getTokenFromHeader();
+ }
//reserved properties
- foreach (['access_token', 'q', 'url', 'action'] as $key) {
+ foreach (['q', 'url', 'action'] as $key) {
if (isset($data[$key])) {
$base->$key = $data[$key];
unset($data[$key]);
}
$json = $base;
$json->properties = (object) $data;
- handleCreate($json);
+ handleCreate($json, $token);
} else if ($ctype == 'application/javascript') {
$input = file_get_contents('php://stdin');
$json = json_decode($input);
if ($json === null) {
- error(
+ mpError(
'HTTP/1.1 400 Bad Request',
'invalid_request',
'Invalid JSON'
);
}
- handleCreate($json);
+ $token = getTokenFromHeader();
+ handleCreate($json, $token);
} else {
- error(
+ mpError(
'HTTP/1.1 400 Bad Request',
'invalid_request',
'Unsupported POST content type'
);
}
} else {
- error(
+ mpError(
'HTTP/1.0 400 Bad Request',
'invalid_request',
'Unsupported HTTP request method'
}
//FIXME: use real decryption
- $data = json_decode($token);
- if ($data === null) {
- error('Invalid token');
+ $encData = base64_decode($token);
+ if ($encData === false) {
+ error('Invalid token data');
}
- $data = (array) $data;
+ parse_str($encData, $data);
+ $emoji = verifyParameter($data, 'emoji');
+ $signature = verifyParameter($data, 'signature');
$me = verifyUrlParameter($data, 'me');
$client_id = verifyUrlParameter($data, 'client_id');
$scope = verifyParameter($data, 'scope');
+ if ($emoji != '\360\237\222\251') {
+ error('Dog poo missing');
+ }
+ if ($signature != 'FIXME') {
+ error('Invalid signature');
+ }
+
header('HTTP/1.0 200 OK');
header('Content-type: application/x-www-form-urlencoded');
echo http_build_query(
$scope = 'post';
//FIXME: use real encryption
- $access_token = '<h1>"\'' . json_encode(
- array(
- 'me' => $me,
- 'client_id' => $client_id,
- 'scope' => $scope
+ $access_token = base64_encode(
+ http_build_query(
+ array(
+ 'emoji' => '\360\237\222\251',
+ 'me' => $me,
+ 'client_id' => $client_id,
+ 'scope' => $scope,
+ 'signature' => 'FIXME',
+ )
)
);
header('HTTP/1.0 200 OK');