Example #1
0
 function postContent()
 {
     $this->gatekeeper();
     $user = Idno::site()->session()->currentUser();
     $url = $this->getInput('url');
     if ($micropub_endpoint = IndieAuthClient::discoverMicropubEndpoint($url)) {
         $auth_endpoint = IndieAuthClient::discoverAuthorizationEndpoint($url);
         $client_id = Idno::site()->config()->getDisplayURL();
         $redirect_uri = Idno::site()->config()->getDisplayURL() . 'account/indiesyndicate/cb';
         $auth_url = IndieAuthClient::buildAuthorizationURL($auth_endpoint, $url, $redirect_uri, $client_id, 'TODO123', 'post');
         $this->forward($auth_url);
     } else {
         $mention_client = new MentionClient();
         if ($webmention_endpoint = $mention_client->discoverWebmentionEndpoint($url)) {
             $name = $this->parseTitle($url);
             $user->indiesyndicate[$url] = ['name' => $name ? $name : $url, 'method' => 'webmention'];
             $user->save();
             Idno::site()->session()->addMessage('Added webmention target ' . $me);
         } else {
             Idno::site()->session()->addMessage('Endpoint does not appear to support Micropub or Webmention: ' . $me);
         }
         $this->forward(Idno::site()->config()->getDisplayURL() . 'account/indiesyndicate');
     }
 }
/**
 * Token Server
 *
 * Create a micropub server app + token provider — creates token-providing and authorizing endpoints, allows users to
 * authorize other apps to make requests to this one on their behalf, authenticates requests based on access tokens.
 * $dataToToken and $dataFromToken map the access token granted to+used by apps and a user+client id+granted scopes
 *
 * Adds routes:
 * /token — clients POST to this URL with a bunch of details, including encrypted state, to gain an access token.
 *
 * Adds ->before() handler which attaches data about the current user, which app they’re using, what scopes they’re
 * granted on this server to $request.
 *
 * @param \Silex\Application $app
 * @param callable|null $dataToToken
 * @param callable|null $dataFromToken
 * @return \Symfony\Component\Routing\RouteCollection
 */
function server($app, $dataToToken = null, $dataFromToken = null)
{
    $auth = $app['controllers_factory'];
    if ($dataToToken === null) {
        $dataToToken = function ($data) use($app) {
            return $app['encryption']->encrypt($data);
        };
    }
    if ($dataFromToken === null) {
        $dataFromToken = function ($token) use($app) {
            return $app['encryption']->decrypt($token);
        };
    }
    $auth->post('/token/', function (Http\Request $request) use($app, $dataToToken) {
        $f = $request->request;
        $me = $f->get('me');
        $code = $f->get('code');
        $clientId = $f->get('client_id');
        $redirectUri = $f->get('redirect_uri');
        $state = $f->get('state');
        // TODO: handle this being false.
        $authorizationEndpoint = IndieAuth\Client::discoverAuthorizationEndpoint(ensureUrlHasHttp($me));
        $auth = IndieAuth\Client::verifyIndieAuthCode($authorizationEndpoint, $code, $me, $redirectUri, $clientId, $state);
        if (isset($auth['error'])) {
            $app['logger']->warning('Got an error whilst verifying an authorization token', ['error' => $auth['error'], 'description' => $auth['error_description'], 'authorizationEndpoint' => $authorizationEndpoint]);
        }
        $tokenData = ['date_issued' => date(DateTime::W3C), 'me' => $auth['me'], 'client_id' => $clientId, 'scope' => isset($auth['scope']) ? $auth['scope'] : '', 'nonce' => mt_rand(1000000, pow(2, 31))];
        $token = $dataToToken($tokenData);
        return Http\Response::create(http_build_query(['me' => $tokenData['me'], 'scope' => $tokenData['scope'], 'access_token' => $token]), 200, ['Content-type' => 'application/x-www-form-urlencoded']);
    })->bind('indieauth.token');
    // TODO: this needs to look in auth headers as well as in the request body
    $app->before(function ($request) use($app, $dataFromToken) {
        if ($request->request->has('access_token')) {
            $app['logger']->info('Authenticating using access token');
            // The user is authenticating using the full indieauth flow.
            // This request is presumably coming from an app which the user has authorized with some access to this site.
            $tokenStr = $request->request->get('access_token');
            try {
                // $token also contains information e.g. the scopes the current user has.
                // Client app filtering could also be done here.
                $token = $dataFromToken($tokenStr);
                // This token has no particularly sensitive information in so can be logged as-is.
                $app['logger']->info('Access token decrypted to', ['data' => $token]);
                $request->attributes->set('indieauth.server.token', $token);
            } catch (Exception $e) {
                $app['logger']->warning("Caught an unhandled exception whilst executing \$dataFromToken — consider updating your handler to deal with these appropriately.", ['exception class' => get_class($e), 'message' => $e->getMessage()]);
            }
        }
    });
    return $auth;
}