Reversion for user auth changes
This commit is contained in:
parent
0b49cf90b3
commit
d1e466a158
|
|
@ -105,11 +105,11 @@ class AccountController extends BaseController
|
|||
|
||||
$company_user = $cu->first();
|
||||
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
// $truth->setCompanyUser($company_user);
|
||||
// $truth->setUser($company_user->user);
|
||||
// $truth->setCompany($company_user->company);
|
||||
// $truth->setCompanyToken($company_user->tokens()->where('user_id', $company_user->user_id)->where('company_id', $company_user->company_id)->first());
|
||||
$truth = app()->make(TruthSource::class);
|
||||
$truth->setCompanyUser($company_user);
|
||||
$truth->setUser($company_user->user);
|
||||
$truth->setCompany($company_user->company);
|
||||
$truth->setCompanyToken($company_user->tokens()->where('user_id', $company_user->user_id)->where('company_id', $company_user->company_id)->first());
|
||||
|
||||
return $this->listResponse($cu);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class ContactResetPasswordController extends Controller
|
|||
|
||||
event(new PasswordReset($user));
|
||||
|
||||
auth()->login($user, true);
|
||||
auth()->login($user, false);
|
||||
|
||||
$response = Password::PASSWORD_RESET;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ use Illuminate\Http\JsonResponse;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
use Microsoft\Graph\Model;
|
||||
|
|
@ -73,6 +72,20 @@ class LoginController extends BaseController
|
|||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Once the user is authenticated, we need to set
|
||||
* the default company into a session variable.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param User $user
|
||||
* @return void
|
||||
* @deprecated .1 API ONLY we don't need to set any session variables
|
||||
*/
|
||||
public function authenticated(Request $request, User $user): void
|
||||
{
|
||||
//$this->setCurrentCompanyId($user->companies()->first()->account->default_company_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login via API.
|
||||
*
|
||||
|
|
@ -83,10 +96,8 @@ class LoginController extends BaseController
|
|||
{
|
||||
$this->forced_includes = ['company_users'];
|
||||
|
||||
/** Checks the required fields for auth are present */
|
||||
$this->validateLogin($request);
|
||||
|
||||
/** Native laravel login throttling */
|
||||
if ($this->hasTooManyLoginAttempts($request)) {
|
||||
$this->fireLockoutEvent($request);
|
||||
|
||||
|
|
@ -96,23 +107,18 @@ class LoginController extends BaseController
|
|||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
}
|
||||
|
||||
// Direct user query based on email and password verification
|
||||
$user = MultiDB::hasUser(['email' => $request->email]);
|
||||
|
||||
if ($user && \Illuminate\Support\Facades\Hash::check(trim($request->password), $user->password)) {
|
||||
//Authenticate for this request only.
|
||||
|
||||
auth()->login($user, false);
|
||||
auth()->user()->setContext($user->account->default_company, $user->tokens()->where('company_id', $user->account->default_company_id)->where('is_system', true)->first());
|
||||
|
||||
if ($this->attemptLogin($request)) {
|
||||
LightLogs::create(new LoginSuccess())
|
||||
->increment()
|
||||
->batch();
|
||||
|
||||
LightLogs::create(new LoginMeta($request->email, $request->ip(), 'success'))
|
||||
LightLogs::create(new LoginMeta($request->email, $request->ip, 'success'))
|
||||
->batch();
|
||||
|
||||
// Process2FA on this request if the parameters are present.
|
||||
/** @var \App\Models\User $user */
|
||||
$user = $this->guard()->user();
|
||||
|
||||
//2FA
|
||||
if ($user->google_2fa_secret && $request->has('one_time_password')) {
|
||||
$google2fa = new Google2FA();
|
||||
|
||||
|
|
@ -140,8 +146,6 @@ class LoginController extends BaseController
|
|||
/** @var \App\Models\CompanyUser $cu */
|
||||
$cu = $this->hydrateCompanyUser();
|
||||
|
||||
nlog("LOGIN:: ".$request->email." {$user->account_id}");
|
||||
|
||||
if ($cu->count() == 0) {
|
||||
return response()->json(['message' => 'User found, but not attached to any companies, please see your administrator'], 400);
|
||||
}
|
||||
|
|
@ -159,7 +163,7 @@ class LoginController extends BaseController
|
|||
->increment()
|
||||
->batch();
|
||||
|
||||
LightLogs::create(new LoginMeta($request->email, $request->ip(), 'failure'))
|
||||
LightLogs::create(new LoginMeta($request->email, $request->ip, 'failure'))
|
||||
->batch();
|
||||
|
||||
$this->incrementLoginAttempts($request);
|
||||
|
|
@ -179,7 +183,13 @@ class LoginController extends BaseController
|
|||
*/
|
||||
public function refresh(Request $request)
|
||||
{
|
||||
$company_token = auth()->user()->getCurrentToken();
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
if ($truth->getCompanyToken()) {
|
||||
$company_token = $truth->getCompanyToken();
|
||||
} else {
|
||||
$company_token = CompanyToken::where('token', $request->header('X-API-TOKEN'))->first();
|
||||
}
|
||||
|
||||
$cu = CompanyUser::query()
|
||||
->where('user_id', $company_token->user_id);
|
||||
|
|
@ -238,27 +248,12 @@ class LoginController extends BaseController
|
|||
->header('X-App-Version', config('ninja.app_version'))
|
||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
}
|
||||
|
||||
/**
|
||||
* getSocialiteUser
|
||||
*
|
||||
* Returns the socialite user if successful
|
||||
* @param string $provider
|
||||
* @param string $token
|
||||
*/
|
||||
|
||||
private function getSocialiteUser(string $provider, string $token)
|
||||
{
|
||||
return Socialite::driver($provider)->userFromToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* handleSocialiteLogin
|
||||
*
|
||||
* Handles authentication for Apple OAuth only!
|
||||
*
|
||||
* @param string $provider
|
||||
* @param string $token
|
||||
*/
|
||||
|
||||
private function handleSocialiteLogin($provider, $token)
|
||||
{
|
||||
$user = $this->getSocialiteUser($provider, $token);
|
||||
|
|
@ -272,13 +267,7 @@ class LoginController extends BaseController
|
|||
->header('X-App-Version', config('ninja.app_version'))
|
||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
}
|
||||
|
||||
/**
|
||||
* loginOrCreateFromSocialite
|
||||
*
|
||||
* @param mixed $user
|
||||
* @param string $provider
|
||||
*/
|
||||
|
||||
private function loginOrCreateFromSocialite($user, $provider)
|
||||
{
|
||||
$query = [
|
||||
|
|
@ -291,8 +280,7 @@ class LoginController extends BaseController
|
|||
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
}
|
||||
|
||||
auth()->login($existing_user, false);
|
||||
auth()->user()->setContext($existing_user->account->default_company, $existing_user->tokens()->where('company_id', $existing_user->account->default_company_id)->where('is_system', true)->first());
|
||||
Auth::login($existing_user, false);
|
||||
|
||||
/** @var \App\Models\CompanyUser $cu */
|
||||
$cu = $this->hydrateCompanyUser();
|
||||
|
|
@ -307,7 +295,39 @@ class LoginController extends BaseController
|
|||
|
||||
return $this->timeConstrainedResponse($cu);
|
||||
}
|
||||
|
||||
//If this is a result user/email combo - lets add their OAuth details details
|
||||
if ($existing_login_user = MultiDB::hasUser(['email' => $user->email])) {
|
||||
if (!$existing_login_user->account) {
|
||||
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
}
|
||||
|
||||
Auth::login($existing_login_user, false);
|
||||
/** @var \App\Models\User $user */
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
$user->update([
|
||||
'oauth_user_id' => $user->id,
|
||||
'oauth_provider_id' => $provider,
|
||||
]);
|
||||
|
||||
/** @var \App\Models\CompanyUser $cu */
|
||||
$cu = $this->hydrateCompanyUser();
|
||||
|
||||
if ($cu->count() == 0) {
|
||||
return response()->json(['message' => 'User found, but not attached to any companies, please see your administrator'], 400);
|
||||
}
|
||||
|
||||
if (Ninja::isHosted() && !$cu->first()->is_owner && !$existing_login_user->account->isEnterprisePaidClient()) {
|
||||
return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403);
|
||||
}
|
||||
|
||||
return $this->timeConstrainedResponse($cu);
|
||||
}
|
||||
|
||||
// nlog("socialite");
|
||||
// nlog($user);
|
||||
|
||||
$name = OAuth::splitName($user->name);
|
||||
|
||||
if ($provider == 'apple') {
|
||||
|
|
@ -332,11 +352,10 @@ class LoginController extends BaseController
|
|||
|
||||
$account = (new CreateAccount($new_account, request()->getClientIp()))->handle();
|
||||
|
||||
$user = $account->users()->first();
|
||||
Auth::login($account->default_company->owner(), false);
|
||||
|
||||
auth()->login($user, false);
|
||||
auth()->user()->setCompany($account->default_company);
|
||||
auth()->user()->setContext($account->default_company, $user->tokens()->where('company_id', $account->default_company_id)->where('is_system', true)->first());
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$user->email_verified_at = now();
|
||||
$user->save();
|
||||
|
|
@ -354,14 +373,7 @@ class LoginController extends BaseController
|
|||
|
||||
return $this->timeConstrainedResponse($cu);
|
||||
}
|
||||
|
||||
/**
|
||||
* hydrateCompanyUser
|
||||
*
|
||||
* Hydrates the company user for the response
|
||||
*
|
||||
* @return Builder
|
||||
*/
|
||||
|
||||
private function hydrateCompanyUser(): Builder
|
||||
{
|
||||
|
||||
|
|
@ -385,12 +397,14 @@ class LoginController extends BaseController
|
|||
|
||||
$this->setLoginCache($user);
|
||||
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
// $truth->setCompanyUser($cu->first());
|
||||
// $truth->setUser($user);
|
||||
// $truth->setCompany($set_company);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
$truth->setCompanyUser($cu->first());
|
||||
$truth->setUser($user);
|
||||
$truth->setCompany($set_company);
|
||||
|
||||
//21-03-2024
|
||||
|
||||
|
||||
$cu->each(function ($cu) {
|
||||
/** @var \App\Models\CompanyUser $cu */
|
||||
if (CompanyToken::query()->where('company_id', $cu->company_id)->where('user_id', $cu->user_id)->where('is_system', true)->doesntExist()) {
|
||||
|
|
@ -398,9 +412,7 @@ class LoginController extends BaseController
|
|||
}
|
||||
});
|
||||
|
||||
// $truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
|
||||
|
||||
$user->setContext($set_company, CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
|
||||
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
|
||||
|
||||
return CompanyUser::query()->where('user_id', $user->id);
|
||||
}
|
||||
|
|
@ -444,17 +456,6 @@ class LoginController extends BaseController
|
|||
return response()->json(['message' => 'User exists, but never authenticated with OAuth, please use your email and password to login.'], 400);
|
||||
}
|
||||
|
||||
// If this is a result user/email combo - lets add their OAuth details details
|
||||
// if ($email && $existing_login_user = MultiDB::hasUser(['email' => $email, 'oauth_provider_id' => 'microsoft'])) {
|
||||
// if (!$existing_login_user->account) {
|
||||
// return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
// }
|
||||
|
||||
// Auth::login($existing_login_user, true);
|
||||
|
||||
// return $this->existingLoginUser($user->getId(), 'microsoft');
|
||||
// }
|
||||
|
||||
// Signup!
|
||||
if (request()->has('create') && request()->input('create') == 'true') {
|
||||
$new_account = [
|
||||
|
|
@ -484,9 +485,7 @@ class LoginController extends BaseController
|
|||
*/
|
||||
private function existingOauthUser($existing_user)
|
||||
{
|
||||
|
||||
auth()->login($existing_user, false);
|
||||
auth()->user()->setContext($existing_user->account->default_company, $existing_user->tokens()->where('company_id', $existing_user->account->default_company->id)->where('is_system', true)->first());
|
||||
Auth::login($existing_user, false);
|
||||
|
||||
/** @var \App\Models\CompanyUser $cu */
|
||||
$cu = $this->hydrateCompanyUser();
|
||||
|
|
@ -502,6 +501,31 @@ class LoginController extends BaseController
|
|||
return $this->timeConstrainedResponse($cu);
|
||||
}
|
||||
|
||||
private function existingLoginUser($oauth_user_id, $provider)
|
||||
{
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$user->update([
|
||||
'oauth_user_id' => $oauth_user_id,
|
||||
'oauth_provider_id' => $provider,
|
||||
]);
|
||||
|
||||
/** @var \App\Models\CompanyUser $cu */
|
||||
$cu = $this->hydrateCompanyUser();
|
||||
|
||||
if ($cu->count() == 0) {
|
||||
return response()->json(['message' => 'User found, but not attached to any companies, please see your administrator'], 400);
|
||||
}
|
||||
|
||||
if (Ninja::isHosted() && !$cu->first()->is_owner && !auth()->user()->account->isEnterprisePaidClient()) {
|
||||
return response()->json(['message' => 'Pro / Free accounts only the owner can log in. Please upgrade'], 403);
|
||||
}
|
||||
|
||||
return $this->timeConstrainedResponse($cu);
|
||||
}
|
||||
|
||||
private function handleGoogleOauth()
|
||||
{
|
||||
$user = false;
|
||||
|
|
@ -534,30 +558,20 @@ class LoginController extends BaseController
|
|||
return response()->json(['message' => 'Please use your email and password to login.'], 400);
|
||||
}
|
||||
|
||||
// 2025-05-19 - this caused an issue when a user/email password combo user used their google account to login, it raced through and attempted to create a new account.
|
||||
//If this is a result user/email combo - lets add their OAuth details details
|
||||
// if ($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user), 'oauth_provider_id' => 'google'])) {
|
||||
// if (!$existing_login_user->account) {
|
||||
// return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
// }
|
||||
|
||||
// Auth::login($existing_login_user, true);
|
||||
|
||||
// return $this->existingLoginUser($google->harvestSubField($user), 'google');
|
||||
// }
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
//check the user doesn't already exist in some form
|
||||
// if ($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user), 'oauth_provider_id' => 'google'])) {
|
||||
// if (!$existing_login_user->account) {
|
||||
// return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
// }
|
||||
if ($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user), 'oauth_provider_id' => 'google'])) {
|
||||
if (!$existing_login_user->account) {
|
||||
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
|
||||
}
|
||||
|
||||
// Auth::login($existing_login_user, true);
|
||||
Auth::login($existing_login_user, false);
|
||||
|
||||
// return $this->existingLoginUser($google->harvestSubField($user), 'google');
|
||||
// }
|
||||
return $this->existingLoginUser($google->harvestSubField($user), 'google');
|
||||
}
|
||||
|
||||
if (request()->has('create') && request()->input('create') == 'true') {
|
||||
//user not found anywhere - lets sign them up.
|
||||
|
|
@ -593,11 +607,10 @@ class LoginController extends BaseController
|
|||
return $account;
|
||||
}
|
||||
|
||||
$user = $account->default_company->owner();
|
||||
// Auth::login($user, true);
|
||||
auth()->login($user, false);
|
||||
auth()->user()->setCompany($account->default_company);
|
||||
auth()->user()->setContext($account->default_company, $user->tokens()->where('company_id', $account->default_company_id)->where('is_system', true)->first());
|
||||
Auth::login($account->default_company->owner(), false);
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$user->email_verified_at = now();
|
||||
$user->save();
|
||||
|
|
|
|||
|
|
@ -12,51 +12,52 @@
|
|||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\ApiSecretCheck;
|
||||
use App\Http\Middleware\Cors;
|
||||
use App\Http\Middleware\SetDb;
|
||||
use App\Http\Middleware\Locale;
|
||||
use App\Http\Middleware\SetWebDb;
|
||||
use App\Http\Middleware\UrlSetDb;
|
||||
use App\Http\Middleware\TokenAuth;
|
||||
use App\Http\Middleware\SetEmailDb;
|
||||
use App\Http\Middleware\VerifyHash;
|
||||
use App\Http\Middleware\SetInviteDb;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
use App\Http\Middleware\Authenticate;
|
||||
use App\Http\Middleware\CheckClientExistence;
|
||||
use App\Http\Middleware\CheckForMaintenanceMode;
|
||||
use App\Http\Middleware\ClientPortalEnabled;
|
||||
use App\Http\Middleware\ContactSetDb;
|
||||
use App\Http\Middleware\QueryLogging;
|
||||
use App\Http\Middleware\TrustProxies;
|
||||
use App\Http\Middleware\UserVerified;
|
||||
use App\Http\Middleware\VendorLocale;
|
||||
use App\Http\Middleware\PhantomSecret;
|
||||
use App\Http\Middleware\SetDocumentDb;
|
||||
use App\Http\Middleware\ApiSecretCheck;
|
||||
use App\Http\Middleware\ContactAccount;
|
||||
use App\Http\Middleware\EncryptCookies;
|
||||
use App\Http\Middleware\SessionDomains;
|
||||
use App\Http\Middleware\ContactKeyLogin;
|
||||
use App\Http\Middleware\ContactRegister;
|
||||
use App\Http\Middleware\ContactSetDb;
|
||||
use App\Http\Middleware\ContactTokenAuth;
|
||||
use App\Http\Middleware\Cors;
|
||||
use App\Http\Middleware\EncryptCookies;
|
||||
use App\Http\Middleware\Locale;
|
||||
use App\Http\Middleware\PasswordProtection;
|
||||
use App\Http\Middleware\PhantomSecret;
|
||||
use App\Http\Middleware\QueryLogging;
|
||||
use App\Http\Middleware\RedirectIfAuthenticated;
|
||||
use App\Http\Middleware\SessionDomains;
|
||||
use App\Http\Middleware\SetDbByCompanyKey;
|
||||
use App\Http\Middleware\SetDocumentDb;
|
||||
use App\Http\Middleware\SetDomainNameDb;
|
||||
use App\Http\Middleware\SetEmailDb;
|
||||
use App\Http\Middleware\SetInviteDb;
|
||||
use App\Http\Middleware\SetWebDb;
|
||||
use App\Http\Middleware\TokenAuth;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
use App\Http\Middleware\TrustProxies;
|
||||
use App\Http\Middleware\UrlSetDb;
|
||||
use App\Http\Middleware\UserVerified;
|
||||
use App\Http\Middleware\ValidateSignature;
|
||||
use App\Http\Middleware\VendorContactKeyLogin;
|
||||
use App\Http\Middleware\VendorLocale;
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use App\Http\Middleware\VerifyHash;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use App\Http\Middleware\ContactTokenAuth;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use App\Http\Middleware\SetDbByCompanyKey;
|
||||
use App\Http\Middleware\ValidateSignature;
|
||||
use App\Http\Middleware\PasswordProtection;
|
||||
use App\Http\Middleware\ClientPortalEnabled;
|
||||
use App\Http\Middleware\CheckClientExistence;
|
||||
use App\Http\Middleware\VendorContactKeyLogin;
|
||||
use Illuminate\Http\Middleware\SetCacheHeaders;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use App\Http\Middleware\CheckForMaintenanceMode;
|
||||
use App\Http\Middleware\RedirectIfAuthenticated;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
|
|
@ -150,6 +151,7 @@ class Kernel extends HttpKernel
|
|||
'portal_enabled' => ClientPortalEnabled::class,
|
||||
'url_db' => UrlSetDb::class,
|
||||
'web_db' => SetWebDb::class,
|
||||
'api_db' => SetDb::class,
|
||||
'company_key_db' => SetDbByCompanyKey::class,
|
||||
'locale' => Locale::class,
|
||||
'vendor_locale' => VendorLocale::class,
|
||||
|
|
@ -172,6 +174,7 @@ class Kernel extends HttpKernel
|
|||
SessionDomains::class,
|
||||
Cors::class,
|
||||
SetDomainNameDb::class,
|
||||
SetDb::class,
|
||||
SetWebDb::class,
|
||||
UrlSetDb::class,
|
||||
ContactSetDb::class,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use stdClass;
|
||||
|
||||
class SetDb
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$error = [
|
||||
'message' => 'Invalid Token',
|
||||
'errors' => new stdClass(),
|
||||
];
|
||||
|
||||
if ($request->header('X-API-TOKEN') && config('ninja.db.multi_db_enabled')) {
|
||||
if (! MultiDB::findAndSetDb($request->header('X-API-TOKEN'))) {
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
} elseif (! config('ninja.db.multi_db_enabled')) {
|
||||
return $next($request);
|
||||
} else {
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,18 +32,18 @@ class TokenAuth
|
|||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (config('ninja.db.multi_db_enabled') &&
|
||||
$request->header('X-API-TOKEN') &&
|
||||
($company_token = MultiDB::getCompanyToken($request->header('X-API-TOKEN')))) {
|
||||
} elseif ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with([
|
||||
|
||||
if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with([
|
||||
'user.account',
|
||||
'company',
|
||||
'account',
|
||||
'cu',
|
||||
])->where('token', $request->header('X-API-TOKEN'))->first())) {
|
||||
|
||||
} else {
|
||||
return response()->json(['message' => 'Invalid token'], 403);
|
||||
}
|
||||
|
||||
$user = $company_token->user;
|
||||
|
||||
$error = [
|
||||
|
|
@ -64,6 +64,24 @@ class TokenAuth
|
|||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
||||
| Necessary evil here: As we are authenticating on CompanyToken,
|
||||
| we need to link the company to the user manually. This allows
|
||||
| us to decouple a $user and their attached companies completely.
|
||||
|
|
||||
*/
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
$truth->setCompanyUser($company_token->cu);
|
||||
$truth->setUser($company_token->user);
|
||||
$truth->setCompany($company_token->company);
|
||||
$truth->setCompanyToken($company_token);
|
||||
$truth->setPremiumHosted($company_token->account->isPremium());
|
||||
/*
|
||||
| This method binds the db to the jobs created using this
|
||||
| session
|
||||
*/
|
||||
app('queue')->createPayloadUsing(function () use ($company_token) {
|
||||
return ['db' => $company_token->company->db];
|
||||
});
|
||||
|
|
@ -81,13 +99,7 @@ class TokenAuth
|
|||
//stateless, don't remember the user.
|
||||
auth()->login($user, false);
|
||||
auth()->user()->setCompany($company_token->company);
|
||||
auth()->user()->setContext($company_token->company, $company_token);
|
||||
|
||||
// Alternative: Bind context to service container for request duration
|
||||
app()->instance('current.company', $company_token->company);
|
||||
app()->instance('current.company_user', $company_token->cu);
|
||||
app()->instance('current.company_token', $company_token);
|
||||
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class BaseImport
|
|||
)
|
||||
: null;
|
||||
|
||||
auth()->login($this->company->owner(), true);
|
||||
auth()->login($this->company->owner(), false);
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
|
|
|||
|
|
@ -115,8 +115,6 @@ class CreateAccount
|
|||
event(new AccountCreated($spaa9f78, $sp035a66, Ninja::eventVars()));
|
||||
}
|
||||
|
||||
//@replaces truthsource
|
||||
auth()->user()->setContext($sp035a66, $sp2d97e8);
|
||||
|
||||
$spaa9f78->fresh();
|
||||
|
||||
|
|
|
|||
|
|
@ -191,108 +191,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
'referral_earnings' => AsReferralEarningCollection::class,
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
private ?Company $contextCompany = null;
|
||||
private ?CompanyUser $contextCompanyUser = null;
|
||||
private ?CompanyToken $contextToken = null;
|
||||
|
||||
// Set context explicitly
|
||||
public function setContext(Company $company, ?CompanyToken $token = null): self
|
||||
{
|
||||
$this->contextCompany = $company;
|
||||
$this->contextToken = $token;
|
||||
$this->contextCompanyUser = $token?->company_user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Transfer context from authenticated user to this instance
|
||||
public function inheritContextFromAuth(): self
|
||||
{
|
||||
if (auth()->check() && auth()->user()->id === $this->id) {
|
||||
$authUser = auth()->user();
|
||||
$this->contextCompany = $authUser->contextCompany;
|
||||
$this->contextToken = $authUser->contextToken;
|
||||
$this->contextCompanyUser = $authUser->contextCompanyUser;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Get current company with fallback chain
|
||||
public function getCurrentCompany(): Company
|
||||
{
|
||||
// 1. Use explicit context if set
|
||||
if ($this->contextCompany) {
|
||||
return $this->contextCompany;
|
||||
}
|
||||
|
||||
// 2. Try service container binding (if available)
|
||||
if (app()->bound('current.company')) {
|
||||
return app('current.company');
|
||||
}
|
||||
|
||||
// 3. Use token-based lookup
|
||||
if ($token = $this->getCurrentToken()) {
|
||||
return $token->company;
|
||||
}
|
||||
|
||||
// 4. Use default company
|
||||
$defaultCompany = $this->companies()->first();
|
||||
if ($defaultCompany instanceof Company) {
|
||||
return $defaultCompany;
|
||||
}
|
||||
|
||||
throw new \Exception('No Company Found for user ID: ' . $this->id);
|
||||
}
|
||||
|
||||
public function getCurrentCompanyUser(): ?CompanyUser
|
||||
{
|
||||
nlog("getcu");
|
||||
|
||||
if ($this->contextCompanyUser) {
|
||||
nlog("level1");
|
||||
return $this->contextCompanyUser;
|
||||
}
|
||||
|
||||
// Try service container binding (if available)
|
||||
if (app()->bound('current.company_user')) {
|
||||
|
||||
nlog("level2");
|
||||
|
||||
return app('current.company_user');
|
||||
}
|
||||
|
||||
$company = $this->getCurrentCompany();
|
||||
|
||||
nlog($company?->id);
|
||||
|
||||
nlog("level3");
|
||||
|
||||
nlog("xxxx ".$this->company_users()->count());
|
||||
nlog("id = ". $this->id);
|
||||
|
||||
return $this->company_users()
|
||||
->where('company_id', $company->id)
|
||||
->where('user_id', $this->id)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function getCurrentToken(): ?CompanyToken
|
||||
{
|
||||
if ($this->contextToken) {
|
||||
return $this->contextToken;
|
||||
}
|
||||
|
||||
if ($apiToken = request()->header('X-API-TOKEN')) {
|
||||
return CompanyToken::where('token', $apiToken)->first();
|
||||
}
|
||||
|
||||
return $this->tokens()->first();
|
||||
}
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->first_name.' '.$this->last_name;
|
||||
|
|
@ -330,19 +228,18 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
|
||||
public function token()
|
||||
{
|
||||
return $this->getCurrentToken();
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
// if ($truth->getCompanyToken()) {
|
||||
// return $truth->getCompanyToken();
|
||||
// }
|
||||
if ($truth->getCompanyToken()) {
|
||||
return $truth->getCompanyToken();
|
||||
}
|
||||
|
||||
// // if (request()->header('X-API-TOKEN')) {
|
||||
// if (request()->header('X-API-TOKEN')) {
|
||||
// return CompanyToken::with(['cu'])->where('token', request()->header('X-API-TOKEN'))->first();
|
||||
// }
|
||||
if (request()->header('X-API-TOKEN')) {
|
||||
return CompanyToken::with(['cu'])->where('token', request()->header('X-API-TOKEN'))->first();
|
||||
}
|
||||
|
||||
// return $this->tokens()->first();
|
||||
return $this->tokens()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -373,20 +270,19 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
*/
|
||||
public function getCompany(): ?Company
|
||||
{
|
||||
return $this->getCurrentCompany();
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
// // @phpstan-ignore-next-line
|
||||
// if ($this->company) {
|
||||
// return $this->company;
|
||||
// } elseif ($truth->getCompany()) {
|
||||
// return $truth->getCompany();
|
||||
// } elseif (request()->header('X-API-TOKEN')) {
|
||||
// $company_token = CompanyToken::with('company')->where('token', request()->header('X-API-TOKEN'))->first();
|
||||
// return $company_token->company;
|
||||
// }
|
||||
// @phpstan-ignore-next-line
|
||||
if ($this->company) {
|
||||
return $this->company;
|
||||
} elseif ($truth->getCompany()) {
|
||||
return $truth->getCompany();
|
||||
} elseif (request()->header('X-API-TOKEN')) {
|
||||
$company_token = CompanyToken::with('company')->where('token', request()->header('X-API-TOKEN'))->first();
|
||||
return $company_token->company;
|
||||
}
|
||||
|
||||
// throw new \Exception('No Company Found');
|
||||
throw new \Exception('No Company Found');
|
||||
}
|
||||
|
||||
public function companyIsSet(): bool
|
||||
|
|
@ -411,30 +307,28 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||
|
||||
public function co_user()
|
||||
{
|
||||
return $this->getCurrentCompanyUser();
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
// if ($truth->getCompanyUser()) {
|
||||
// return $truth->getCompanyUser();
|
||||
// }
|
||||
if ($truth->getCompanyUser()) {
|
||||
return $truth->getCompanyUser();
|
||||
}
|
||||
|
||||
// return $this->token()->cu;
|
||||
return $this->token()->cu;
|
||||
}
|
||||
|
||||
public function company_user()
|
||||
{
|
||||
return $this->getCurrentCompanyUser();
|
||||
// if ($this->companyId()) {
|
||||
// return $this->belongsTo(CompanyUser::class)->where('company_id', $this->companyId())->withTrashed();
|
||||
// }
|
||||
if ($this->companyId()) {
|
||||
return $this->belongsTo(CompanyUser::class)->where('company_id', $this->companyId())->withTrashed();
|
||||
}
|
||||
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
// if ($truth->getCompanyUser()) {
|
||||
// return $truth->getCompanyUser();
|
||||
// }
|
||||
if ($truth->getCompanyUser()) {
|
||||
return $truth->getCompanyUser();
|
||||
}
|
||||
|
||||
// return $this->token()->cu;
|
||||
return $this->token()->cu;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@ class AppServiceProvider extends ServiceProvider
|
|||
});
|
||||
|
||||
/* Ensure we don't have stale state in jobs */
|
||||
// Queue::before(function (JobProcessing $event) {
|
||||
// App::forgetInstance(TruthSource::class);
|
||||
// });
|
||||
Queue::before(function (JobProcessing $event) {
|
||||
App::forgetInstance(TruthSource::class);
|
||||
});
|
||||
|
||||
app()->instance(TruthSource::class, new TruthSource());
|
||||
|
||||
/* Extension for custom mailers */
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class UserRepository extends BaseRepository
|
|||
/*No company user exists - attach the user*/
|
||||
if (! $cu) {
|
||||
$data['company_user']['account_id'] = $account->id;
|
||||
$data['company_user']['notifications'] = CompanySettings::notificationDefaults();
|
||||
$data['company_user']['notifications'] = isset($data['company_user']['notifications']['email']) ? $data['company_user']['notifications'] : CompanySettings::notificationDefaults();
|
||||
$user->companies()->attach($company->id, $data['company_user']);
|
||||
} else {
|
||||
if (auth()->user()->isAdmin()) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ Route::group(['middleware' => ['throttle:login', 'api_secret_check', 'email_db']
|
|||
Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail']);
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['throttle:api', 'token_auth', 'valid_json','locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'valid_json','locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
|
||||
Route::post('password_timeout', PasswordTimeoutController::class)->name('password_timeout');
|
||||
Route::put('accounts/{account}', [AccountController::class, 'update'])->name('account.update');
|
||||
|
|
|
|||
|
|
@ -121,10 +121,10 @@ class CsvImportTest extends TestCase
|
|||
|
||||
// $this->user->setContext($this->company, $this->token);
|
||||
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
// $truth->setCompanyUser($this->cu);
|
||||
// $truth->setUser($this->user);
|
||||
// $truth->setCompany($this->company);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
$truth->setCompanyUser($this->cu);
|
||||
$truth->setUser($this->user);
|
||||
$truth->setCompany($this->company);
|
||||
|
||||
$csv_importer = new Csv($data, $this->company);
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,14 @@ class UserTest extends TestCase
|
|||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
auth()->user()->setContext($company, $company_token);
|
||||
// auth()->user()->setContext($company, $company_token);
|
||||
|
||||
$truth = app()->make(TruthSource::class);
|
||||
|
||||
$truth->setCompanyUser($company_token->cu);
|
||||
$truth->setUser($company_token->user);
|
||||
$truth->setCompany($company_token->company);
|
||||
$truth->setCompanyToken($company_token);
|
||||
|
||||
return $company_token;
|
||||
|
||||
|
|
|
|||
|
|
@ -295,12 +295,12 @@ trait MockAccountData
|
|||
|
||||
$company_token->save();
|
||||
|
||||
$user->setContext($this->company, $company_token);
|
||||
// $user->setContext($this->company, $company_token);
|
||||
|
||||
// $truth = app()->make(TruthSource::class);
|
||||
// $truth->setCompanyUser($company_token->first());
|
||||
// $truth->setUser($this->user);
|
||||
// $truth->setCompany($this->company);
|
||||
$truth = app()->make(TruthSource::class);
|
||||
$truth->setCompanyUser($company_token->first());
|
||||
$truth->setUser($this->user);
|
||||
$truth->setCompany($this->company);
|
||||
|
||||
//todo create one token with token name TOKEN - use firstOrCreate
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue