kopia lustrzana https://github.com/pixelfed/pixelfed
				
				
				
			Initial in-app registration logic
							rodzic
							
								
									b79d808c3b
								
							
						
					
					
						commit
						772cfb9cee
					
				|  | @ -14,12 +14,18 @@ use App\EmailVerification; | |||
| use App\Status; | ||||
| use App\Report; | ||||
| use App\Profile; | ||||
| use App\User; | ||||
| use App\Services\AccountService; | ||||
| use App\Services\StatusService; | ||||
| use App\Services\ProfileStatusService; | ||||
| use App\Util\Lexer\RestrictedNames; | ||||
| use App\Services\EmailService; | ||||
| use Illuminate\Support\Str; | ||||
| use Illuminate\Support\Facades\Hash; | ||||
| use Jenssegers\Agent\Agent; | ||||
| use Mail; | ||||
| use App\Mail\PasswordChange; | ||||
| use App\Mail\ConfirmAppEmail; | ||||
| 
 | ||||
| class ApiV1Dot1Controller extends Controller | ||||
| { | ||||
|  | @ -402,4 +408,145 @@ class ApiV1Dot1Controller extends Controller | |||
| 
 | ||||
|         return $this->json($res); | ||||
|     } | ||||
| 
 | ||||
|     public function inAppRegistrationPreFlightCheck(Request $request) | ||||
|     { | ||||
|         return [ | ||||
|             'open' => config('pixelfed.open_registration'), | ||||
|             'iara' => config('pixelfed.allow_app_registration') | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function inAppRegistration(Request $request) | ||||
|     { | ||||
|         abort_if($request->user(), 404); | ||||
|         abort_unless(config('pixelfed.open_registration'), 404); | ||||
|         abort_unless(config('pixelfed.allow_app_registration'), 404); | ||||
|         abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); | ||||
|         $this->validate($request, [ | ||||
|             'email' => [ | ||||
|                 'required', | ||||
|                 'string', | ||||
|                 'email', | ||||
|                 'max:255', | ||||
|                 'unique:users', | ||||
|                 function ($attribute, $value, $fail) { | ||||
|                     $banned = EmailService::isBanned($value); | ||||
|                     if($banned) { | ||||
|                         return $fail('Email is invalid.'); | ||||
|                     } | ||||
|                 }, | ||||
|             ], | ||||
|             'username' => [ | ||||
|                 'required', | ||||
|                 'min:2', | ||||
|                 'max:15', | ||||
|                 'unique:users', | ||||
|                 function ($attribute, $value, $fail) { | ||||
|                     $dash = substr_count($value, '-'); | ||||
|                     $underscore = substr_count($value, '_'); | ||||
|                     $period = substr_count($value, '.'); | ||||
| 
 | ||||
|                     if(ends_with($value, ['.php', '.js', '.css'])) { | ||||
|                         return $fail('Username is invalid.'); | ||||
|                     } | ||||
| 
 | ||||
|                     if(($dash + $underscore + $period) > 1) { | ||||
|                         return $fail('Username is invalid. Can only contain one dash (-), period (.) or underscore (_).'); | ||||
|                     } | ||||
| 
 | ||||
|                     if (!ctype_alnum($value[0])) { | ||||
|                         return $fail('Username is invalid. Must start with a letter or number.'); | ||||
|                     } | ||||
| 
 | ||||
|                     if (!ctype_alnum($value[strlen($value) - 1])) { | ||||
|                         return $fail('Username is invalid. Must end with a letter or number.'); | ||||
|                     } | ||||
| 
 | ||||
|                     $val = str_replace(['_', '.', '-'], '', $value); | ||||
|                     if(!ctype_alnum($val)) { | ||||
|                         return $fail('Username is invalid. Username must be alpha-numeric and may contain dashes (-), periods (.) and underscores (_).'); | ||||
|                     } | ||||
| 
 | ||||
|                     $restricted = RestrictedNames::get(); | ||||
|                     if (in_array(strtolower($value), array_map('strtolower', $restricted))) { | ||||
|                         return $fail('Username cannot be used.'); | ||||
|                     } | ||||
|                 }, | ||||
|             ], | ||||
|             'password' => 'required|string|min:8', | ||||
|             // 'avatar' => 'required|mimetypes:image/jpeg,image/png|max:15000',
 | ||||
|             // 'bio' => 'required|max:140'
 | ||||
|         ]); | ||||
| 
 | ||||
|         $email = $request->input('email'); | ||||
|         $username = $request->input('username'); | ||||
|         $password = $request->input('password'); | ||||
| 
 | ||||
|         if(config('database.default') == 'pgsql') { | ||||
|             $username = strtolower($username); | ||||
|             $email = strtolower($email); | ||||
|         } | ||||
| 
 | ||||
|         $user = new User; | ||||
|         $user->name = $username; | ||||
|         $user->username = $username; | ||||
|         $user->email = $email; | ||||
|         $user->password = Hash::make($password); | ||||
|         $user->register_source = 'app'; | ||||
|         $user->app_register_ip = $request->ip(); | ||||
|         $user->app_register_token = Str::random(32); | ||||
|         $user->save(); | ||||
| 
 | ||||
|         $rtoken = Str::random(mt_rand(64, 70)); | ||||
| 
 | ||||
|         $verify = new EmailVerification(); | ||||
|         $verify->user_id = $user->id; | ||||
|         $verify->email = $user->email; | ||||
|         $verify->user_token = $user->app_register_token; | ||||
|         $verify->random_token = $rtoken; | ||||
|         $verify->save(); | ||||
| 
 | ||||
|         $appUrl = 'pixelfed://confirm-account/'. $user->app_register_token . '?rt=' . $rtoken; | ||||
| 
 | ||||
|         Mail::to($user->email)->send(new ConfirmAppEmail($verify, $appUrl)); | ||||
| 
 | ||||
|         return response()->json([ | ||||
|             'success' => true, | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     public function inAppRegistrationConfirm(Request $request) | ||||
|     { | ||||
|         abort_if($request->user(), 404); | ||||
|         abort_unless(config('pixelfed.open_registration'), 404); | ||||
|         abort_unless(config('pixelfed.allow_app_registration'), 404); | ||||
|         abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); | ||||
|         $this->validate($request, [ | ||||
|             'user_token' => 'required', | ||||
|             'random_token' => 'required', | ||||
|             'email' => 'required' | ||||
|         ]); | ||||
| 
 | ||||
|         $verify = EmailVerification::whereEmail($request->input('email')) | ||||
|             ->whereUserToken($request->input('user_token')) | ||||
|             ->whereRandomToken($request->input('random_token')) | ||||
|             ->first(); | ||||
| 
 | ||||
|         if(!$verify) { | ||||
|             return response()->json(['error' => 'Invalid tokens'], 403); | ||||
|         } | ||||
| 
 | ||||
|         $user = User::findOrFail($verify->user_id); | ||||
|         $user->email_verified_at = now(); | ||||
|         $user->save(); | ||||
| 
 | ||||
|         $verify->delete(); | ||||
| 
 | ||||
|         $token = $user->createToken('Pixelfed'); | ||||
| 
 | ||||
|         return response()->json([ | ||||
|             'access_token' => $token->access_token | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -276,4 +276,6 @@ return [ | |||
| 	'media_fast_process' => env('PF_MEDIA_FAST_PROCESS', true), | ||||
| 
 | ||||
| 	'max_altext_length' => env('PF_MEDIA_MAX_ALTTEXT_LENGTH', 1000), | ||||
| 
 | ||||
| 	'allow_app_registration' => env('PF_ALLOW_APP_REGISTRATION', true), | ||||
| ]; | ||||
|  |  | |||
|  | @ -0,0 +1,36 @@ | |||
| <?php | ||||
| 
 | ||||
| use Illuminate\Database\Migrations\Migration; | ||||
| use Illuminate\Database\Schema\Blueprint; | ||||
| use Illuminate\Support\Facades\Schema; | ||||
| 
 | ||||
| return new class extends Migration | ||||
| { | ||||
|     /** | ||||
|      * Run the migrations. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function up() | ||||
|     { | ||||
|         Schema::table('users', function (Blueprint $table) { | ||||
|             $table->string('register_source')->default('web')->nullable()->index(); | ||||
|             $table->string('app_register_token')->nullable(); | ||||
|             $table->string('app_register_ip')->nullable(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reverse the migrations. | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     public function down() | ||||
|     { | ||||
|         Schema::table('users', function (Blueprint $table) { | ||||
|             $table->dropColumn('register_source'); | ||||
|             $table->dropColumn('app_register_token'); | ||||
|             $table->dropColumn('app_register_ip'); | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
|  | @ -149,6 +149,12 @@ Route::group(['prefix' => 'api'], function() use($middleware) { | |||
| 		Route::group(['prefix' => 'directory'], function () use($middleware) { | ||||
| 			Route::get('listing', 'PixelfedDirectoryController@get'); | ||||
| 		}); | ||||
| 
 | ||||
| 		Route::group(['prefix' => 'auth'], function () use($middleware) { | ||||
| 			Route::get('iarpfc', 'Api\ApiV1Dot1Controller@inAppRegistrationPreFlightCheck'); | ||||
| 			Route::post('iar', 'Api\ApiV1Dot1Controller@inAppRegistration'); | ||||
| 			Route::post('iarc', 'Api\ApiV1Dot1Controller@inAppRegistrationConfirm'); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	Route::group(['prefix' => 'live'], function() use($middleware) { | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Daniel Supernault
						Daniel Supernault