planiverse

A minimalist, no-JS front-end for Mastodon.
git clone https://git.mulligrubs.me/planiverse
Log | Files | Refs | README | LICENSE

commit 144848225f750cf8fa00067268d03c6622947b7e
parent d7a3e81cff4ed4dc54294bd3f32c8dace5f4d1ee
Author: St John Karp <stjohn@fuzzjunket.com>
Date:   Sun, 12 Aug 2018 07:26:26 -0700

Support login workflow

Added basic support for logging in and viewing your home timeline.
Created a sqlite DB for managing app credentials.

Diffstat:
Aapp/Http/Controllers/LoginController.php | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mapp/Http/Controllers/TimelineController.php | 32++++++++++++++++++++++++++------
Mcomposer.json | 3++-
Mcomposer.lock | 182++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mconfig/services.php | 8++++++++
Mconfig/session.php | 2+-
Ddatabase/migrations/2014_10_12_000000_create_users_table.php | 35-----------------------------------
Ddatabase/migrations/2014_10_12_100000_create_password_resets_table.php | 32--------------------------------
Adatabase/migrations/2018_08_11_175433_create_apps_table.php | 38++++++++++++++++++++++++++++++++++++++
Mroutes/web.php | 14+++++++++++++-
10 files changed, 341 insertions(+), 78 deletions(-)

diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php @@ -0,0 +1,73 @@ +<?php + +namespace App\Http\Controllers; + +use App\Http\Controllers\Controller; +use Mastodon; +use Illuminate\Support\Facades\DB; +use Socialite; + +class LoginController extends Controller +{ + public function login() + { + # Check if this app is already registered. + $app = DB::table('apps')->where('server', env('MASTODON_DOMAIN'))->first(); + + if ($app == null) + { + # Register this app with the API server. + $app_info = Mastodon::domain(env('MASTODON_DOMAIN')) + ->createApp(env('APP_NAME'), env('MASTODON_REDIRECT'), config('services.mastodon.scopes'), env('APP_URL')); + + $client_id = $app_info['client_id']; + $client_secret = $app_info['client_secret']; + + DB::table('apps')->insert([ + 'server' => env('MASTODON_DOMAIN'), + 'client_name' => env('APP_NAME'), + 'redirect_uris' => env('MASTODON_REDIRECT'), + 'scopes' => join(' ', config('services.mastodon.scopes')), + 'website' => env('APP_URL'), + 'response_id' => $app_info['id'], + 'client_id' => $client_id, + 'client_secret' => $client_secret + ]); + } + else + { + $client_id = $app->client_id; + $client_secret = $app->client_secret; + } + + # Set configs required for the redirect. + config(['services.mastodon.domain' => env('MASTODON_DOMAIN')]); + config(['services.mastodon.client_id' => $client_id]); + config(['services.mastodon.client_secret' => $client_secret]); + + # Save this info to the session. + session(['mastodon_domain' => env('MASTODON_DOMAIN')]); + session(['client_id' => $client_id]); + session(['client_secret' => $client_secret]); + + # Redirect the user to their instance to log in. + return Socialite::driver('mastodon')->redirect(); + } + + public function callback() + { + $domain = session('mastodon_domain'); + $client_id = session('client_id'); + $client_secret = session('client_secret'); + + config(['services.mastodon.domain' => $domain]); + config(['services.mastodon.client_id' => $client_id]); + config(['services.mastodon.client_secret' => $client_secret]); + + # Get user data (token, etc.) + $user = Socialite::driver('mastodon')->user(); + session(['user' => $user]); + + return redirect()->route('friends'); + } +} diff --git a/app/Http/Controllers/TimelineController.php b/app/Http/Controllers/TimelineController.php @@ -7,21 +7,41 @@ use Mastodon; class TimelineController extends Controller { - public function show_timeline() + public function public_timeline() { - $public_timeline = Mastodon::domain(env('MASTODON_API')) + $timeline = Mastodon::domain(env('MASTODON_DOMAIN')) ->get('/timelines/public', ['local' => true]); - # Embed images. - foreach ($public_timeline as $index => $status) + $timeline = $this->embed_images($timeline); + + return view('timeline', ['statuses' => $timeline]); + } + + public function home_timeline() + { + $user = session('user'); + $timeline = Mastodon::domain(env('MASTODON_DOMAIN')) + ->token($user->token) + ->get('/timelines/home'); + + $timeline = $this->embed_images($timeline); + + return view('timeline', ['statuses' => $timeline]); + } + + private function embed_images($timeline) + { + foreach ($timeline as $index => $status) { - $public_timeline[$index]['content'] = preg_replace( + # Search for links to images and replace the inner HTML + # with an img tag of the image itself. + $timeline[$index]['content'] = preg_replace( '/<a href="([^>]+)\.(png|jpg|jpeg|gif)">([^<]+)<\/a>/', '<a href="${1}.${2}"><img src="${1}.${2}" alt="${3}" /></a>', $status['content'] ); } - return view('timeline', ['statuses' => $public_timeline]); + return $timeline; } } diff --git a/composer.json b/composer.json @@ -9,7 +9,8 @@ "fideloper/proxy": "~3.3", "laravel/framework": "5.5.*", "laravel/tinker": "~1.0", - "revolution/laravel-mastodon-api": "^1.5" + "revolution/laravel-mastodon-api": "^1.5", + "revolution/socialite-mastodon": "^1.2" }, "require-dev": { "filp/whoops": "~2.0", diff --git a/composer.lock b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "92f25db138dc11525945a2c977eff7a9", - "content-hash": "fe6ad9502bf61c169c783babe3aac2e8", + "hash": "777e302fe64df7b4f6c3d53b0d67ca01", + "content-hash": "99e2b15adf8ee6829bad59f44cae2cef", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -724,6 +724,68 @@ "time": "2018-08-08 18:22:44" }, { + "name": "laravel/socialite", + "version": "v3.0.12", + "source": { + "type": "git", + "url": "https://github.com/laravel/socialite.git", + "reference": "b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/socialite/zipball/b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f", + "reference": "b5f465847b1d637efa86bbfe2fc1c9d2bd12f60f", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "~6.0", + "illuminate/contracts": "~5.4", + "illuminate/http": "~5.4", + "illuminate/support": "~5.4", + "league/oauth1-client": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.0|~5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Socialite\\SocialiteServiceProvider" + ], + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + } + } + }, + "autoload": { + "psr-4": { + "Laravel\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "keywords": [ + "laravel", + "oauth" + ], + "time": "2018-06-01 15:06:47" + }, + { "name": "laravel/tinker", "version": "v1.0.7", "source": { @@ -871,6 +933,69 @@ "time": "2018-05-07 08:44:23" }, { + "name": "league/oauth1-client", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "fca5f160650cb74d23fc11aa570dd61f86dcf647" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/fca5f160650cb74d23fc11aa570dd61f86dcf647", + "reference": "fca5f160650cb74d23fc11aa570dd61f86dcf647", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0" + }, + "require-dev": { + "mockery/mockery": "^0.9", + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "time": "2016-08-17 00:36:58" + }, + { "name": "monolog/monolog", "version": "1.23.0", "source": { @@ -1551,6 +1676,59 @@ "time": "2018-05-17 06:29:25" }, { + "name": "revolution/socialite-mastodon", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/kawax/socialite-mastodon.git", + "reference": "2c5f26cee466fabf5797de46f8a55b5537abfe17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kawax/socialite-mastodon/zipball/2c5f26cee466fabf5797de46f8a55b5537abfe17", + "reference": "2c5f26cee466fabf5797de46f8a55b5537abfe17", + "shasum": "" + }, + "require": { + "laravel/socialite": "*", + "php": ">=7.0.0." + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Revolution\\Socialite\\Mastodon\\MastodonServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Revolution\\Socialite\\Mastodon\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "kawax", + "email": "kawaxbiz@gmail.com" + } + ], + "description": "Socialite for Mastodon", + "keywords": [ + "laravel", + "mastodon", + "socialite" + ], + "time": "2018-05-10 03:45:17" + }, + { "name": "swiftmailer/swiftmailer", "version": "v6.1.2", "source": { diff --git a/config/services.php b/config/services.php @@ -35,4 +35,12 @@ return [ 'secret' => env('STRIPE_SECRET'), ], + 'mastodon' => [ + 'domain' => env('MASTODON_DOMAIN'), + 'client_id' => env('MASTODON_ID'), + 'client_secret' => env('MASTODON_SECRET'), + 'redirect' => env('MASTODON_REDIRECT'), + //'read', 'write', 'follow' + 'scope' => ['read', 'write', 'follow'], + ], ]; diff --git a/config/session.php b/config/session.php @@ -44,7 +44,7 @@ return [ | */ - 'encrypt' => false, + 'encrypt' => true, /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php @@ -1,35 +0,0 @@ -<?php - -use Illuminate\Support\Facades\Schema; -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Migrations\Migration; - -class CreateUsersTable extends Migration -{ - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::create('users', function (Blueprint $table) { - $table->increments('id'); - $table->string('name'); - $table->string('email')->unique(); - $table->string('password'); - $table->rememberToken(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('users'); - } -} diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php @@ -1,32 +0,0 @@ -<?php - -use Illuminate\Support\Facades\Schema; -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Migrations\Migration; - -class CreatePasswordResetsTable extends Migration -{ - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::create('password_resets', function (Blueprint $table) { - $table->string('email')->index(); - $table->string('token'); - $table->timestamp('created_at')->nullable(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('password_resets'); - } -} diff --git a/database/migrations/2018_08_11_175433_create_apps_table.php b/database/migrations/2018_08_11_175433_create_apps_table.php @@ -0,0 +1,38 @@ +<?php + +use Illuminate\Support\Facades\Schema; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +class CreateAppsTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::create('apps', function (Blueprint $table) { + $table->increments('id'); + $table->char('server'); + $table->char('client_name'); + $table->char('redirect_uris'); + $table->char('scopes'); + $table->char('website'); + $table->char('response_id'); + $table->char('client_id'); + $table->char('client_secret'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('apps'); + } +} diff --git a/routes/web.php b/routes/web.php @@ -11,4 +11,16 @@ | */ -Route::get('/', 'TimelineController@show_timeline'); +Route::get('/', function() { + return redirect()->route('public'); +}); + +Route::get('/timeline/public', 'TimelineController@public_timeline') + ->name('public'); + +Route::get('/timeline/friends', 'TimelineController@home_timeline') + ->name('friends'); + +Route::get('/login', 'LoginController@login'); + +Route::get('/callback', 'LoginController@callback');