123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- <?php
- namespace App\Http\Controllers;
- use App\Mail\InAppRegisterEmailVerify;
- use App\Models\AppRegister;
- use App\Services\AccountService;
- use App\User;
- use App\Util\Lexer\RestrictedNames;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Hash;
- use Illuminate\Support\Facades\Mail;
- use Illuminate\Support\Str;
- use Laravel\Passport\RefreshTokenRepository;
- use Purify;
- class AppRegisterController extends Controller
- {
- public function index(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- return view('auth.iar');
- }
- public function store(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- $rules = [
- 'email' => 'required|email:rfc,dns,spoof,strict|unique:users,email|unique:app_registers,email',
- ];
- if ((bool) config_cache('captcha.enabled') && (bool) config_cache('captcha.active.register')) {
- $rules['h-captcha-response'] = 'required|captcha';
- }
- $this->validate($request, $rules);
- $email = strtolower($request->input('email'));
- $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
- DB::beginTransaction();
- $exists = AppRegister::whereEmail($email)->where('created_at', '>', now()->subHours(24))->count();
- if ($exists && $exists > 3) {
- $errorParams = http_build_query([
- 'status' => 'error',
- 'message' => 'Too many attempts, please try again later.',
- ]);
- DB::rollBack();
- return redirect()->away("pixelfed://verifyEmail?{$errorParams}");
- }
- $registration = AppRegister::create([
- 'email' => $email,
- 'verify_code' => $code,
- 'uses' => 1,
- 'email_delivered_at' => now(),
- ]);
- try {
- Mail::to($email)->send(new InAppRegisterEmailVerify($code));
- } catch (\Exception $e) {
- DB::rollBack();
- $errorParams = http_build_query([
- 'status' => 'error',
- 'message' => 'Failed to send verification code',
- ]);
- return redirect()->away("pixelfed://verifyEmail?{$errorParams}");
- }
- DB::commit();
- $queryParams = http_build_query([
- 'email' => $request->email,
- 'expires_in' => 3600,
- 'status' => 'success',
- ]);
- return redirect()->away("pixelfed://verifyEmail?{$queryParams}");
- }
- public function verifyCode(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- $this->validate($request, [
- 'email' => 'required|email:rfc,dns,spoof,strict|unique:users,email',
- 'verify_code' => ['required', 'digits:6', 'numeric'],
- ]);
- $email = strtolower($request->input('email'));
- $code = $request->input('verify_code');
- $exists = AppRegister::whereEmail($email)
- ->whereVerifyCode($code)
- ->where('created_at', '>', now()->subMinutes(60))
- ->exists();
- return response()->json([
- 'status' => $exists ? 'success' : 'error',
- ]);
- }
- public function resendVerification(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- return view('auth.iar-resend');
- }
- public function resendVerificationStore(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- $rules = [
- 'email' => 'required|email:rfc,dns,spoof,strict|unique:users,email|exists:app_registers,email',
- ];
- if ((bool) config_cache('captcha.enabled') && (bool) config_cache('captcha.active.register')) {
- $rules['h-captcha-response'] = 'required|captcha';
- }
- $this->validate($request, $rules);
- $email = strtolower($request->input('email'));
- $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
- DB::beginTransaction();
- $exists = AppRegister::whereEmail($email)->first();
- if (! $exists || $exists->uses > 5) {
- $errorMessage = $exists->uses > 5 ? 'Too many attempts have been made, please contact the admins.' : 'Email not found';
- $errorParams = http_build_query([
- 'status' => 'error',
- 'message' => $errorMessage,
- ]);
- DB::rollBack();
- return redirect()->away("pixelfed://verifyEmail?{$errorParams}");
- }
- $registration = $exists->update([
- 'verify_code' => $code,
- 'uses' => ($exists->uses + 1),
- 'email_delivered_at' => now(),
- ]);
- try {
- Mail::to($email)->send(new InAppRegisterEmailVerify($code));
- } catch (\Exception $e) {
- DB::rollBack();
- $errorParams = http_build_query([
- 'status' => 'error',
- 'message' => 'Failed to send verification code',
- ]);
- return redirect()->away("pixelfed://verifyEmail?{$errorParams}");
- }
- DB::commit();
- $queryParams = http_build_query([
- 'email' => $request->email,
- 'expires_in' => 3600,
- 'status' => 'success',
- ]);
- return redirect()->away("pixelfed://verifyEmail?{$queryParams}");
- }
- public function onboarding(Request $request)
- {
- abort_unless(config('auth.in_app_registration'), 404);
- $open = (bool) config_cache('pixelfed.open_registration');
- if (! $open || $request->user()) {
- return redirect('/');
- }
- $this->validate($request, [
- 'email' => 'required|email:rfc,dns,spoof,strict|unique:users,email',
- 'verify_code' => ['required', 'digits:6', 'numeric'],
- 'username' => $this->validateUsernameRule(),
- 'name' => 'nullable|string|max:'.config('pixelfed.max_name_length'),
- 'password' => 'required|string|min:'.config('pixelfed.min_password_length'),
- ]);
- $email = strtolower($request->input('email'));
- $code = $request->input('verify_code');
- $username = $request->input('username');
- $name = $request->input('name');
- $password = $request->input('password');
- $exists = AppRegister::whereEmail($email)
- ->whereVerifyCode($code)
- ->where('created_at', '>', now()->subMinutes(60))
- ->exists();
- if (! $exists) {
- return response()->json([
- 'status' => 'error',
- 'message' => 'Invalid verification code, please try again later.',
- ]);
- }
- $user = User::create([
- 'name' => Purify::clean($name),
- 'username' => $username,
- 'email' => $email,
- 'password' => Hash::make($password),
- 'app_register_ip' => request()->ip(),
- 'register_source' => 'app',
- 'email_verified_at' => now(),
- ]);
- sleep(random_int(8, 10));
- $user = User::findOrFail($user->id);
- $token = $user->createToken('Pixelfed App', ['read', 'write', 'follow', 'push']);
- $tokenModel = $token->token;
- $clientId = $tokenModel->client_id;
- $clientSecret = DB::table('oauth_clients')->where('id', $clientId)->value('secret');
- $refreshTokenRepo = app(RefreshTokenRepository::class);
- $refreshToken = $refreshTokenRepo->create([
- 'id' => Str::random(80),
- 'access_token_id' => $tokenModel->id,
- 'revoked' => false,
- 'expires_at' => now()->addDays(config('instance.oauth.refresh_expiration', 400)),
- ]);
- $expiresAt = $tokenModel->expires_at ?? now()->addDays(config('instance.oauth.token_expiration', 356));
- $expiresIn = now()->diffInSeconds($expiresAt);
- return response()->json([
- 'status' => 'success',
- 'token_type' => 'Bearer',
- 'domain' => config('pixelfed.domain.app'),
- 'expires_in' => $expiresIn,
- 'access_token' => $token->accessToken,
- 'refresh_token' => $refreshToken->id,
- 'client_id' => $clientId,
- 'client_secret' => $clientSecret,
- 'scope' => ['read', 'write', 'follow', 'push'],
- 'user' => [
- 'pid' => (string) $user->profile_id,
- 'username' => $user->username,
- ],
- 'account' => AccountService::get($user->profile_id, true),
- ]);
- }
- protected function validateUsernameRule()
- {
- return [
- 'required',
- 'min:2',
- 'max:30',
- '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 (_).');
- }
- if (! preg_match('/[a-zA-Z]/', $value)) {
- return $fail('Username is invalid. Must contain at least one alphabetical character.');
- }
- $restricted = RestrictedNames::get();
- if (in_array(strtolower($value), array_map('strtolower', $restricted))) {
- return $fail('Username cannot be used.');
- }
- },
- ];
- }
- }
|