Merge branch 'release/0.11'
This commit is contained in:
commit
d33cee84b9
36 changed files with 854 additions and 1770 deletions
|
|
@ -54,7 +54,6 @@ before_script:
|
|||
- php artisan key:generate
|
||||
- php artisan migrate
|
||||
- php artisan db:seed
|
||||
- php artisan token:generate
|
||||
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9515 http://localhost:8000 &
|
||||
|
||||
script:
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\IndieWebUser;
|
||||
use App\Services\TokenService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class GenerateToken extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'token:generate';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Generate a token that can be used for testing purposes';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* The token service class.
|
||||
*
|
||||
* @var TokenService
|
||||
*/
|
||||
protected $tokenService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(TokenService $tokenService)
|
||||
{
|
||||
$data = [
|
||||
'me' => config('app.url'),
|
||||
'client_id' => route('micropub-client'),
|
||||
'scope' => 'create update',
|
||||
];
|
||||
$token = $tokenService->getNewToken($data);
|
||||
$user = IndieWebUser::where('me', config('app.url'))->first();
|
||||
$user->token = $token;
|
||||
$user->save();
|
||||
|
||||
$this->info('Set token');
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ class Kernel extends ConsoleKernel
|
|||
Commands\SecurityCheck::class,
|
||||
Commands\ParseCachedWebMentions::class,
|
||||
Commands\ReDownloadWebMentions::class,
|
||||
Commands\GenerateToken::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\IndieWebUser;
|
||||
use IndieAuth\Client;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class IndieAuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* The IndieAuth Client.
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Inject the dependency.
|
||||
*
|
||||
* @param \IndieAuth\Client $client
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin the indie auth process. This method ties in to the login page
|
||||
* from our micropub client. Here we then query the user’s homepage
|
||||
* for their authorisation endpoint, and redirect them there with a
|
||||
* unique secure state value.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||
*/
|
||||
public function start(Request $request)
|
||||
{
|
||||
$url = normalize_url($request->input('me'));
|
||||
$authorizationEndpoint = $this->client->discoverAuthorizationEndpoint($url);
|
||||
if ($authorizationEndpoint != null) {
|
||||
$state = bin2hex(openssl_random_pseudo_bytes(16));
|
||||
session(['state' => $state]);
|
||||
$authorizationURL = $this->client->buildAuthorizationURL(
|
||||
$authorizationEndpoint,
|
||||
$url,
|
||||
route('indieauth-callback'), //redirect_uri
|
||||
route('micropub-client'), //client_id
|
||||
$state
|
||||
);
|
||||
if ($authorizationURL) {
|
||||
return redirect($authorizationURL);
|
||||
}
|
||||
|
||||
return redirect(route('micropub-client'))->with('error', 'Error building authorization URL');
|
||||
}
|
||||
|
||||
return redirect(route('micropub-client'))->with('error', 'Unable to determine authorisation endpoint');
|
||||
}
|
||||
|
||||
/**
|
||||
* Once they have verified themselves through the authorisation endpoint
|
||||
* the next step is register/login the user.
|
||||
*
|
||||
* @param \Illuminate\Http\Rrequest $request
|
||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||
*/
|
||||
public function callback(Request $request)
|
||||
{
|
||||
if ($request->session()->get('state') != $request->input('state')) {
|
||||
return redirect(route('micropub-client'))->with(
|
||||
'error',
|
||||
'Invalid <code>state</code> value returned from indieauth server'
|
||||
);
|
||||
}
|
||||
|
||||
$url = normalize_url($request->input('me'));
|
||||
$indiewebUser = IndieWebUser::firstOrCreate(['me' => $url]);
|
||||
$request->session()->put(['me' => $url]);
|
||||
|
||||
return redirect(route('micropub-client'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log out the user, flush the session data.
|
||||
*
|
||||
* @return \Illuminate\Routing\RedirectResponse redirect
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$request->session()->flush();
|
||||
|
||||
return redirect(route('micropub-client'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,548 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\IndieWebUser;
|
||||
use Illuminate\Http\{Request, Response};
|
||||
use GuzzleHttp\Exception\{ClientException, ServerException};
|
||||
|
||||
class MicropubClientController extends Controller
|
||||
{
|
||||
/**
|
||||
* Inject the dependencies.
|
||||
*/
|
||||
public function __construct(
|
||||
\IndieAuth\Client $indieClient,
|
||||
\GuzzleHttp\Client $guzzleClient
|
||||
) {
|
||||
$this->indieClient = $indieClient;
|
||||
$this->guzzleClient = $guzzleClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the new notes form.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\View\Factory view
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
//initiate varaibles
|
||||
$indiewebUser = null;
|
||||
$syndication = null;
|
||||
$mediaEndpoint = null;
|
||||
$mediaURLs = null;
|
||||
$url = $request->session()->get('me');
|
||||
if ($url) {
|
||||
$indiewebUser = IndieWebUser::where('me', $url)->first();
|
||||
}
|
||||
if ($indiewebUser) {
|
||||
$syndication = $this->parseSyndicationTargets($indiewebUser->syndication);
|
||||
$mediaEndpoint = $indiewebUser->mediaEndpoint ?? null;
|
||||
$mediaURLs = $request->session()->get('media-links');
|
||||
}
|
||||
|
||||
return view('micropub.create', compact('url', 'syndication', 'mediaEndpoint', 'mediaURLs'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an upload to the media endpoint.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request
|
||||
* @return Illuminate\Http\Response
|
||||
*/
|
||||
public function processMedia(Request $request)
|
||||
{
|
||||
if ($request->hasFile('files') == false) {
|
||||
return back()->with('error', 'No files uploaded');
|
||||
}
|
||||
|
||||
$user = IndieWebUser::where('me', $request->session()->get('me'))->firstOrFail();
|
||||
if ($user->mediaEndpoint == null || $user->token == null) {
|
||||
return back()->with('error', 'No user token or known endpoint');
|
||||
}
|
||||
|
||||
$mediaURLs = [];
|
||||
foreach ($request->file('files') as $file) {
|
||||
try {
|
||||
$response = $this->guzzleClient->request('POST', $user->mediaEndpoint, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $user->token,
|
||||
],
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'file',
|
||||
'contents' => fopen($file->path(), 'r'),
|
||||
'filename' => $file->getClientOriginalName(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
} catch (ClientException | ServerException $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mediaURLs[] = $response->getHeader('Location')[0];
|
||||
}
|
||||
|
||||
$storedMediaURLs = $request->session()->get('media-links') ?? [];
|
||||
$mediaURLsToSave = array_merge($storedMediaURLs, $mediaURLs);
|
||||
$request->session()->put('media-links', $mediaURLsToSave);
|
||||
|
||||
return redirect()->route('micropub-client');
|
||||
}
|
||||
|
||||
public function clearLinks(Request $request)
|
||||
{
|
||||
$request->session()->forget('media-links');
|
||||
|
||||
return redirect(route('micropub-client'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Post the notes content to the relavent micropub API endpoint.
|
||||
*
|
||||
* @todo make sure this works with multiple syndication targets
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$url = normalize_url($request->session()->get('me'));
|
||||
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||
|
||||
if ($user->token == null) {
|
||||
return redirect()->route('micropub-client')->with('error', 'You haven’t requested a token yet');
|
||||
}
|
||||
|
||||
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||
if (! $micropubEndpoint) {
|
||||
return redirect()->route('micropub-client')->with('error', 'Unable to determine micropub API endpoint');
|
||||
}
|
||||
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $user->token,
|
||||
];
|
||||
|
||||
if ($user->syntax == 'html') {
|
||||
$multipart = [
|
||||
[
|
||||
'name' => 'h',
|
||||
'contents' => 'entry',
|
||||
],
|
||||
[
|
||||
'name' => 'content',
|
||||
'contents' => $request->input('content'),
|
||||
],
|
||||
];
|
||||
if ($request->hasFile('photo')) {
|
||||
$photos = $request->file('photo');
|
||||
foreach ($photos as $photo) {
|
||||
$multipart[] = [
|
||||
'name' => 'photo[]',
|
||||
'contents' => fopen($photo->path(), 'r'),
|
||||
'filename' => $photo->getClientOriginalName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($request->input('in-reply-to') != '') {
|
||||
$multipart[] = [
|
||||
'name' => 'in-reply-to',
|
||||
'contents' => $request->input('in-reply-to'),
|
||||
];
|
||||
}
|
||||
if ($request->input('mp-syndicate-to')) {
|
||||
foreach ($request->input('mp-syndicate-to') as $syn) {
|
||||
$multipart[] = [
|
||||
'name' => 'mp-syndicate-to[]',
|
||||
'contents' => $syn,
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($request->input('location')) {
|
||||
if ($request->input('location') !== 'no-location') {
|
||||
$multipart[] = [
|
||||
'name' => 'location',
|
||||
'contents' => $request->input('location'),
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($request->input('media')) {
|
||||
foreach ($request->input('media') as $media) {
|
||||
$multipart[] = [
|
||||
'name' => 'photo[]',
|
||||
'contents' => $media,
|
||||
];
|
||||
}
|
||||
}
|
||||
try {
|
||||
$response = $this->guzzleClient->post($micropubEndpoint, [
|
||||
'multipart' => $multipart,
|
||||
'headers' => $headers,
|
||||
]);
|
||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||
return redirect()->route('micropub-client')->with(
|
||||
'error',
|
||||
'There was a bad response from the micropub endpoint.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() == 201) {
|
||||
$request->session()->forget('media-links');
|
||||
$location = $response->getHeader('Location');
|
||||
if (is_array($location)) {
|
||||
return redirect($location[0]);
|
||||
}
|
||||
|
||||
return redirect($location);
|
||||
}
|
||||
}
|
||||
|
||||
if ($user->syntax == 'json') {
|
||||
$json = [];
|
||||
$json['type'] = ['h-entry'];
|
||||
$json['properties'] = ['content' => [$request->input('content')]];
|
||||
|
||||
if ($request->input('in-reply-to') != '') {
|
||||
$json['properties']['in-reply-to'][] = $request->input('in-reply-to');
|
||||
}
|
||||
if ($request->input('mp-syndicate-to')) {
|
||||
foreach ($request->input('mp-syndicate-to') as $syn) {
|
||||
$json['properties']['mp-syndicate-to'][] = $syn;
|
||||
}
|
||||
}
|
||||
if ($request->input('location')) {
|
||||
if ($request->input('location') !== 'no-location') {
|
||||
$json['properties']['location'][] = $request->input('location');
|
||||
}
|
||||
}
|
||||
if ($request->input('media')) {
|
||||
$json['properties']['photo'] = [];
|
||||
foreach ($request->input('media') as $media) {
|
||||
$json['properties']['photo'][] = $media;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->guzzleClient->post($micropubEndpoint, [
|
||||
'json' => $json,
|
||||
'headers' => $headers,
|
||||
]);
|
||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||
return redirect()->route('micropub-client')->with(
|
||||
'error',
|
||||
'There was a bad response from the micropub endpoint.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() == 201) {
|
||||
$request->session()->forget('media-links');
|
||||
$location = $response->getHeader('Location');
|
||||
if (is_array($location)) {
|
||||
return redirect($location[0]);
|
||||
}
|
||||
|
||||
return redirect($location);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('micropub-client')->with('error', 'Endpoint didn’t create the note.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show currently stored configuration values.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request
|
||||
* @return view
|
||||
*/
|
||||
public function config(Request $request)
|
||||
{
|
||||
//default values
|
||||
$data = [
|
||||
'me' => '',
|
||||
'token' => 'none',
|
||||
'syndication' => 'none defined',
|
||||
'media-endpoint' => 'none defined',
|
||||
'syntax' => 'html',
|
||||
];
|
||||
if ($request->session()->has('me')) {
|
||||
$data['me'] = normalize_url($request->session()->get('me'));
|
||||
$user = IndieWebUser::where('me', $request->session()->get('me'))->firstOrFail();
|
||||
$data['token'] = $user->token ?? 'none defined';
|
||||
$data['syndication'] = $user->syndication ?? 'none defined';
|
||||
$data['media-endpoint'] = $user->mediaEndpoint ?? 'none defined';
|
||||
$data['syntax'] = $user->syntax;
|
||||
}
|
||||
|
||||
return view('micropub.config', compact('data'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new token.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request
|
||||
* @return view
|
||||
*/
|
||||
public function getNewToken(Request $request)
|
||||
{
|
||||
if ($request->session()->has('me')) {
|
||||
$url = normalize_url($request->session()->get('me'));
|
||||
$authozationEndpoint = $this->indieClient->discoverAuthorizationEndpoint($url);
|
||||
if ($authozationEndpoint) {
|
||||
$state = bin2hex(random_bytes(16));
|
||||
$request->session()->put('state', $state);
|
||||
$authorizationURL = $this->indieClient->buildAuthorizationURL(
|
||||
$authozationEndpoint,
|
||||
$url,
|
||||
route('micropub-client-get-new-token-callback'), // redirect_uri
|
||||
route('micropub-client'), //client_id
|
||||
$state,
|
||||
'create update' // scope needs to be a setting
|
||||
);
|
||||
|
||||
return redirect($authorizationURL);
|
||||
}
|
||||
|
||||
return redirect()->route('micropub-config')->with('error', 'Unable to find authorisation endpoint');
|
||||
}
|
||||
|
||||
return redirect()->route('micropub-config')->with('error', 'You aren’t logged in');
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback for getting a token.
|
||||
*/
|
||||
public function getNewTokenCallback(Request $request)
|
||||
{
|
||||
if ($request->input('state') !== $request->session()->get('state')) {
|
||||
return redirect()->route('micropub-config')->with('error', 'The <code>state</code> didn’t match.');
|
||||
}
|
||||
$tokenEndpoint = $this->indieClient->discoverTokenEndpoint(normalize_url($request->input('me')));
|
||||
if ($tokenEndpoint) {
|
||||
$token = $this->indieClient->getAccessToken(
|
||||
$tokenEndpoint,
|
||||
$request->input('code'),
|
||||
$request->input('me'),
|
||||
route('micropub-client-get-new-token-callback'), // redirect_uri
|
||||
route('micropub-client') // client_id
|
||||
);
|
||||
if (array_key_exists('access_token', $token)) {
|
||||
$url = normalize_url($token['me']);
|
||||
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||
$user->token = $token['access_token'];
|
||||
$user->save();
|
||||
|
||||
return redirect()->route('micropub-config');
|
||||
}
|
||||
|
||||
return redirect()->route('micropub-config')->with('error', 'Error getting token from the endpoint');
|
||||
}
|
||||
|
||||
return redirect()->route('micropub-config')->with('error', 'Unable to find token endpoint');
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the micropub endpoint and store response.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request
|
||||
* @return redirect
|
||||
*/
|
||||
public function queryEndpoint(Request $request)
|
||||
{
|
||||
$url = normalize_url($request->session()->get('me'));
|
||||
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||
$token = $user->token;
|
||||
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||
if ($micropubEndpoint) {
|
||||
try {
|
||||
$response = $this->guzzleClient->get($micropubEndpoint, [
|
||||
'headers' => ['Authorization' => 'Bearer ' . $token],
|
||||
'query' => 'q=config',
|
||||
]);
|
||||
} catch (ClientException | ServerException $e) {
|
||||
return back();
|
||||
}
|
||||
$body = (string) $response->getBody();
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (array_key_exists('syndicate-to', $data)) {
|
||||
$user->syndication = json_encode($data['syndicate-to']);
|
||||
}
|
||||
|
||||
if (array_key_exists('media-endpoint', $data)) {
|
||||
$user->mediaEndpoint = $data['media-endpoint'];
|
||||
}
|
||||
$user->save();
|
||||
|
||||
return back();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the syntax setting.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request
|
||||
* @return Illuminate\Http\RedirectResponse
|
||||
* @todo validate input
|
||||
*/
|
||||
public function updateSyntax(Request $request)
|
||||
{
|
||||
$user = IndieWebUser::where('me', $request->session()->get('me'))->firstOrFail();
|
||||
$user->syntax = $request->syntax;
|
||||
$user->save();
|
||||
|
||||
return redirect()->route('micropub-config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new place.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function newPlace(Request $request)
|
||||
{
|
||||
$url = normalize_url($request->session()->get('me'));
|
||||
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||
|
||||
if ($user->token === null) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'No known token',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||
if (! $micropubEndpoint) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'Could not determine the micropub endpoint.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$formParams = [
|
||||
'h' => 'card',
|
||||
'name' => $request->input('place-name'),
|
||||
'description' => $request->input('place-description'),
|
||||
'geo' => 'geo:' . $request->input('place-latitude') . ',' . $request->input('place-longitude'),
|
||||
];
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $user->token,
|
||||
];
|
||||
try {
|
||||
$response = $this->guzzleClient->request('POST', $micropubEndpoint, [
|
||||
'form_params' => $formParams,
|
||||
'headers' => $headers,
|
||||
]);
|
||||
} catch (ClientException $e) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'Unable to create the new place',
|
||||
], 400);
|
||||
}
|
||||
$place = $response->getHeader('Location')[0];
|
||||
|
||||
return response()->json([
|
||||
'uri' => $place,
|
||||
'name' => $request->input('place-name'),
|
||||
'latitude' => $request->input('place-latitude'),
|
||||
'longitude' => $request->input('place-longitude'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to the micropub endpoint requesting any nearby places.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function nearbyPlaces(Request $request)
|
||||
{
|
||||
$url = normalize_url($request->session()->get('me'));
|
||||
$user = IndieWebUser::where('me', $url)->firstOrFail();
|
||||
|
||||
if ($user->token === null) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'No known token',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$micropubEndpoint = $this->indieClient->discoverMicropubEndpoint($url);
|
||||
|
||||
if (! $micropubEndpoint) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'No known endpoint',
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
$query = 'geo:' . $request->input('latitude') . ',' . $request->input('longitude');
|
||||
if ($request->input('u') !== null) {
|
||||
$query .= ';u=' . $request->input('u');
|
||||
}
|
||||
$response = $this->guzzleClient->get($micropubEndpoint, [
|
||||
'headers' => ['Authorization' => 'Bearer ' . $user->token],
|
||||
'query' => ['q' => $query],
|
||||
]);
|
||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'error_description' => 'The endpoint ' . $micropubEndpoint . ' returned a non-good response',
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response($response->getBody(), 200)
|
||||
->header('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the syndication targets JSON into a an array.
|
||||
*
|
||||
* @param string|null
|
||||
* @return array|null
|
||||
*/
|
||||
private function parseSyndicationTargets($syndicationTargets = null)
|
||||
{
|
||||
if ($syndicationTargets === null || $syndicationTargets === '') {
|
||||
return;
|
||||
}
|
||||
$syndicateTo = [];
|
||||
$data = json_decode($syndicationTargets, true);
|
||||
if (array_key_exists('uid', $data)) {
|
||||
$syndicateTo[] = [
|
||||
'target' => $data['uid'],
|
||||
'name' => $data['name'],
|
||||
];
|
||||
}
|
||||
foreach ($data as $syn) {
|
||||
if (array_key_exists('uid', $syn)) {
|
||||
$syndicateTo[] = [
|
||||
'target' => $syn['uid'],
|
||||
'name' => $syn['name'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $syndicateTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the media-endpoint retrieved from querying a micropub endpoint.
|
||||
*
|
||||
* @param string|null
|
||||
* @return string
|
||||
*/
|
||||
private function parseMediaEndpoint($queryResponse = null)
|
||||
{
|
||||
if ($queryResponse === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = json_decode($queryResponse, true);
|
||||
if (array_key_exists('media-endpoint', $data)) {
|
||||
return $data['media-endpoint'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class IndieWebUser extends Model
|
||||
{
|
||||
/**
|
||||
* Mass assignment protection.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['me'];
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use IndieAuth\Client;
|
||||
|
||||
class IndieAuthService
|
||||
{
|
||||
protected $client;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new Client();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a domain, determing the assocaited authorization endpoint,
|
||||
* if one exists.
|
||||
*
|
||||
* @param string The domain
|
||||
* @return string|null
|
||||
*/
|
||||
public function getAuthorizationEndpoint(string $domain): ?string
|
||||
{
|
||||
$endpoint = $this->client->discoverAuthorizationEndpoint($this->client->normalizeMeURL($domain));
|
||||
if ($endpoint === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an authorization endpoint, build the appropriate authorization URL.
|
||||
*
|
||||
* @param string $authEndpoint
|
||||
* @param string $domain
|
||||
* @return string
|
||||
*/
|
||||
public function buildAuthorizationURL(string $authEndpoint, string $domain): string
|
||||
{
|
||||
$state = bin2hex(openssl_random_pseudo_bytes(16));
|
||||
session(['state' => $state]);
|
||||
$redirectURL = route('indieauth-callback');
|
||||
$clientId = route('micropub-client');
|
||||
$authorizationURL = $this->client->buildAuthorizationURL(
|
||||
$authEndpoint,
|
||||
$this->client->normalizeMeURL($domain),
|
||||
$redirectURL,
|
||||
$clientId,
|
||||
$state
|
||||
);
|
||||
|
||||
return $authorizationURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover the token endpoint for a given domain.
|
||||
*
|
||||
* @param string The domain
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTokenEndpoint(string $domain): ?string
|
||||
{
|
||||
return $this->client->discoverTokenEndpoint($this->client->normalizeMeURL($domain));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a token from the token endpoint.
|
||||
*
|
||||
* @param array The relavent data
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken(array $data): array
|
||||
{
|
||||
return $this->client->getAccessToken(
|
||||
$data['endpoint'],
|
||||
$data['code'],
|
||||
$data['me'],
|
||||
$data['redirect_url'],
|
||||
$data['client_id'],
|
||||
$data['state']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the Authorization endpoint, then verify the suplied code is
|
||||
* valid.
|
||||
*
|
||||
* @param array The data.
|
||||
* @return array|null
|
||||
*/
|
||||
public function verifyIndieAuthCode(array $data): ?array
|
||||
{
|
||||
$authEndpoint = $this->client->discoverAuthorizationEndpoint($data['me']);
|
||||
if ($authEndpoint) {
|
||||
return $this->client->verifyIndieAuthCode(
|
||||
$authEndpoint,
|
||||
$data['code'],
|
||||
$data['me'],
|
||||
$data['redirect_url'],
|
||||
$data['client_id'],
|
||||
$data['state']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the micropub endpoint.
|
||||
*
|
||||
* @param string $domain
|
||||
* @return string|null The endpoint
|
||||
*/
|
||||
public function discoverMicropubEndpoint(string $domain): ?string
|
||||
{
|
||||
return $this->client->discoverMicropubEndpoint($this->client->normalizeMeURL($domain));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
# Changelog
|
||||
|
||||
## Version 0.11 (2017-10-19)
|
||||
- No more built-in micropub client
|
||||
|
||||
## Version 0.10 (20017-10-13)
|
||||
- Bookmarks!
|
||||
- They can only be added via micropub
|
||||
|
|
|
|||
76
composer.lock
generated
76
composer.lock
generated
|
|
@ -8,16 +8,16 @@
|
|||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.36.23",
|
||||
"version": "3.36.29",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "755ff10ad2ea4ebb04b4e2b150a4a4fb13a22060"
|
||||
"reference": "210958295921f0004d0fdc38bc9aefe33ef2a3de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/755ff10ad2ea4ebb04b4e2b150a4a4fb13a22060",
|
||||
"reference": "755ff10ad2ea4ebb04b4e2b150a4a4fb13a22060",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/210958295921f0004d0fdc38bc9aefe33ef2a3de",
|
||||
"reference": "210958295921f0004d0fdc38bc9aefe33ef2a3de",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -84,7 +84,7 @@
|
|||
"s3",
|
||||
"sdk"
|
||||
],
|
||||
"time": "2017-10-06T22:26:58+00:00"
|
||||
"time": "2017-10-18T18:46:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barnabywalters/mf-cleaner",
|
||||
|
|
@ -1940,16 +1940,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.5.14",
|
||||
"version": "v5.5.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "26c700eb79e5bb55b59df2c495c9c71f16f43302"
|
||||
"reference": "3a16d196bd8d2b7761c9b0060a30a3687c3ea201"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/26c700eb79e5bb55b59df2c495c9c71f16f43302",
|
||||
"reference": "26c700eb79e5bb55b59df2c495c9c71f16f43302",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/3a16d196bd8d2b7761c9b0060a30a3687c3ea201",
|
||||
"reference": "3a16d196bd8d2b7761c9b0060a30a3687c3ea201",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2068,7 +2068,7 @@
|
|||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2017-10-03T17:41:03+00:00"
|
||||
"time": "2017-10-17T12:19:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/horizon",
|
||||
|
|
@ -3630,16 +3630,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "6.4.0",
|
||||
"version": "6.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "a1bcaca096998de32c29535fdd2dea0c475e8f61"
|
||||
"reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1bcaca096998de32c29535fdd2dea0c475e8f61",
|
||||
"reference": "a1bcaca096998de32c29535fdd2dea0c475e8f61",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/06b28548fd2b4a20c3cd6e247dc86331a7d4db13",
|
||||
"reference": "06b28548fd2b4a20c3cd6e247dc86331a7d4db13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3710,7 +3710,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-10-06T03:14:57+00:00"
|
||||
"time": "2017-10-16T13:18:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
|
|
@ -4079,16 +4079,16 @@
|
|||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.8.11",
|
||||
"version": "v0.8.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "b193cd020e8c6b66cea6457826ae005e94e6d2c0"
|
||||
"reference": "cdb5593c3684bab74e10fcfffe4a0c8d1c39695d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/b193cd020e8c6b66cea6457826ae005e94e6d2c0",
|
||||
"reference": "b193cd020e8c6b66cea6457826ae005e94e6d2c0",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/cdb5593c3684bab74e10fcfffe4a0c8d1c39695d",
|
||||
"reference": "cdb5593c3684bab74e10fcfffe4a0c8d1c39695d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4148,7 +4148,7 @@
|
|||
"interactive",
|
||||
"shell"
|
||||
],
|
||||
"time": "2017-07-29T19:30:02+00:00"
|
||||
"time": "2017-10-19T06:13:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
|
|
@ -5571,16 +5571,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.5.0",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803"
|
||||
"reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803",
|
||||
"reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
|
||||
"reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5592,7 +5592,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.5-dev"
|
||||
"dev-master": "1.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
|
@ -5626,7 +5626,7 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2017-06-14T15:44:48+00:00"
|
||||
"time": "2017-10-11T12:05:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
|
|
@ -6346,16 +6346,16 @@
|
|||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.1.10",
|
||||
"version": "2.1.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec"
|
||||
"reference": "a99f0b151846021ba7a73b4e3cba3ebc9f14f03e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec",
|
||||
"reference": "ffbbd2c06c64b08fb47974eed5dbce4ca2bb0eec",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/a99f0b151846021ba7a73b4e3cba3ebc9f14f03e",
|
||||
"reference": "a99f0b151846021ba7a73b4e3cba3ebc9f14f03e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -6400,10 +6400,10 @@
|
|||
"exception",
|
||||
"handling",
|
||||
"library",
|
||||
"whoops",
|
||||
"zf2"
|
||||
"throwable",
|
||||
"whoops"
|
||||
],
|
||||
"time": "2017-08-03T18:23:40+00:00"
|
||||
"time": "2017-10-15T13:05:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fzaninotto/faker",
|
||||
|
|
@ -6549,16 +6549,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/dusk",
|
||||
"version": "v2.0.6",
|
||||
"version": "v2.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/dusk.git",
|
||||
"reference": "322de1489d7b5a09b7a04758e2dd71586a07b046"
|
||||
"reference": "29127c21d72ab5bff53ed3b8eb914c0059c77763"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/dusk/zipball/322de1489d7b5a09b7a04758e2dd71586a07b046",
|
||||
"reference": "322de1489d7b5a09b7a04758e2dd71586a07b046",
|
||||
"url": "https://api.github.com/repos/laravel/dusk/zipball/29127c21d72ab5bff53ed3b8eb914c0059c77763",
|
||||
"reference": "29127c21d72ab5bff53ed3b8eb914c0059c77763",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -6606,7 +6606,7 @@
|
|||
"testing",
|
||||
"webdriver"
|
||||
],
|
||||
"time": "2017-10-02T14:18:54+00:00"
|
||||
"time": "2017-10-09T16:10:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maximebf/debugbar",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class DatabaseSeeder extends Seeder
|
|||
$this->call(PlacesTableSeeder::class);
|
||||
$this->call(NotesTableSeeder::class);
|
||||
$this->call(WebMentionsTableSeeder::class);
|
||||
$this->call(IndieWebUserTableSeeder::class);
|
||||
$this->call(LikesTableSeeder::class);
|
||||
$this->call(BookmarksTableSeeder::class);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
use App\IndieWebUser;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class IndieWebUserTableSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
IndieWebUser::create(['me' => config('app.url')]);
|
||||
}
|
||||
}
|
||||
1401
package-lock.json
generated
1401
package-lock.json
generated
File diff suppressed because it is too large
Load diff
26
package.json
26
package.json
|
|
@ -6,36 +6,36 @@
|
|||
"license": "CC0-1.0",
|
||||
"dependencies": {
|
||||
"alertify.js": "^1.0.12",
|
||||
"mapbox-gl": "^0.39.1",
|
||||
"mapbox-gl": "^0.41.0",
|
||||
"marked": "^0.3.6",
|
||||
"normalize.css": "^7.0.0",
|
||||
"webStorage": "^1.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ajv": "^5.2.2",
|
||||
"autoprefixer": "^7.1.4",
|
||||
"ajv": "^5.2.3",
|
||||
"autoprefixer": "^7.1.5",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"babel-preset-latest": "^6.16.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"dotenv-webpack": "^1.5.4",
|
||||
"eslint": "^4.6.1",
|
||||
"eslint": "^4.9.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-plugin-import": "^2.7.0",
|
||||
"eslint-plugin-node": "^5.1.1",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-node": "^5.2.0",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"lint-staged": "^4.1.3",
|
||||
"postcss-cli": "^4.1.0",
|
||||
"lint-staged": "^4.3.0",
|
||||
"postcss-cli": "^4.1.1",
|
||||
"pre-commit": "^1.1.3",
|
||||
"source-list-map": "^2.0.0",
|
||||
"stylelint": "^8.1.1",
|
||||
"stylelint": "^8.2.0",
|
||||
"stylelint-config-standard": "^17.0.0",
|
||||
"uglify-js": "^3.0.28",
|
||||
"webpack": "^3.5.6",
|
||||
"uglify-js": "^3.1.4",
|
||||
"webpack": "^3.8.1",
|
||||
"webpack-sources": "^1.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
2
public/assets/js/maps.js
vendored
2
public/assets/js/maps.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
2
public/assets/js/newnote.js
vendored
2
public/assets/js/newnote.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue