ImpersonateManager   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 245
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 8
dl 0
loc 245
rs 9.68
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getLeaveRedirectTo() 0 10 2
A getSessionGuardUsing() 0 4 1
A clear() 0 6 1
A findUserById() 0 30 5
A isImpersonating() 0 4 1
A getImpersonatorId() 0 4 1
A getImpersonator() 0 6 2
A getImpersonatorGuardName() 0 4 1
A getImpersonatorGuardUsingName() 0 4 1
A take() 0 22 2
A leave() 0 22 2
A getSessionKey() 0 4 1
A getSessionGuard() 0 4 1
A getDefaultSessionGuard() 0 4 1
A getTakeRedirectTo() 0 10 2
A getCurrentAuthGuardName() 0 12 3
A saveAuthCookieInSession() 0 15 3
A extractAuthCookieFromSession() 0 9 2
A findByKeyInArray() 0 7 1
1
<?php
2
3
namespace Lab404\Impersonate\Services;
4
5
use Exception;
6
use Illuminate\Contracts\Auth\Guard;
7
use Illuminate\Contracts\Auth\UserProvider;
8
use Illuminate\Database\Eloquent\ModelNotFoundException;
9
use Illuminate\Foundation\Application;
10
use Lab404\Impersonate\Events\LeaveImpersonation;
11
use Lab404\Impersonate\Events\TakeImpersonation;
12
use Lab404\Impersonate\Exceptions\InvalidUserProvider;
13
use Lab404\Impersonate\Exceptions\MissingUserProvider;
14
15
class ImpersonateManager
16
{
17
    const REMEMBER_PREFIX = 'remember_web';
18
19
    /** @var Application $app */
20
    private $app;
21
22
    public function __construct(Application $app)
23
    {
24
        $this->app = $app;
25
    }
26
27
    /**
28
     * @param int $id
29
     * @return \Illuminate\Contracts\Auth\Authenticatable
30
     * @throws MissingUserProvider
31
     * @throws InvalidUserProvider
32
     * @throws ModelNotFoundException
33
     */
34
    public function findUserById($id, $guardName = null)
35
    {
36
        if (empty($guardName)) {
37
            $guardName = $this->app['config']->get('auth.default.guard', 'web');
38
        }
39
40
        $providerName = $this->app['config']->get("auth.guards.$guardName.provider");
41
42
        if (empty($providerName)) {
43
            throw new MissingUserProvider($guardName);
44
        }
45
46
        try {
47
            /** @var UserProvider $userProvider */
48
            $userProvider = $this->app['auth']->createUserProvider($providerName);
49
        } catch (\InvalidArgumentException $e) {
50
            throw new InvalidUserProvider($guardName);
51
        }
52
53
        if (!($modelInstance = $userProvider->retrieveById($id))) {
54
            $model = $this->app['config']->get("auth.providers.$providerName.model");
55
56
            throw (new ModelNotFoundException())->setModel(
57
                $model,
58
                $id
59
            );
60
        }
61
62
        return $modelInstance;
63
    }
64
65
    public function isImpersonating(): bool
66
    {
67
        return session()->has($this->getSessionKey());
68
    }
69
70
    /**
71
     * @return  int|null
72
     */
73
    public function getImpersonatorId()
74
    {
75
        return session($this->getSessionKey(), null);
76
    }
77
78
    /**
79
     * @return \Illuminate\Contracts\Auth\Authenticatable
80
     */
81
    public function getImpersonator()
82
    {
83
        $id = session($this->getSessionKey(), null);
84
85
        return is_null($id) ? null : $this->findUserById($id, $this->getImpersonatorGuardName());
86
    }
87
88
    /**
89
     * @return string|null
90
     */
91
    public function getImpersonatorGuardName()
92
    {
93
        return session($this->getSessionGuard(), null);
94
    }
95
96
    /**
97
     * @return string|null
98
     */
99
    public function getImpersonatorGuardUsingName()
100
    {
101
        return session($this->getSessionGuardUsing(), null);
102
    }
103
104
    /**
105
     * @param \Illuminate\Contracts\Auth\Authenticatable $from
106
     * @param \Illuminate\Contracts\Auth\Authenticatable $to
107
     * @param string|null                         $guardName
108
     * @return bool
109
     */
110
    public function take($from, $to, $guardName = null)
111
    {
112
        $this->saveAuthCookieInSession();
113
114
        try {
115
            $currentGuard = $this->getCurrentAuthGuardName();
116
            session()->put($this->getSessionKey(), $from->getAuthIdentifier());
117
            session()->put($this->getSessionGuard(), $currentGuard);
118
            session()->put($this->getSessionGuardUsing(), $guardName);
119
120
            $this->app['auth']->guard($currentGuard)->quietLogout();
121
            $this->app['auth']->guard($guardName)->quietLogin($to);
122
123
        } catch (\Exception $e) {
124
            unset($e);
125
            return false;
126
        }
127
128
        $this->app['events']->dispatch(new TakeImpersonation($from, $to));
129
130
        return true;
131
    }
132
133
    public function leave(): bool
134
    {
135
        try {
136
            $impersonated = $this->app['auth']->guard($this->getImpersonatorGuardUsingName())->user();
137
            $impersonator = $this->findUserById($this->getImpersonatorId(), $this->getImpersonatorGuardName());
138
139
            $this->app['auth']->guard($this->getCurrentAuthGuardName())->quietLogout();
140
            $this->app['auth']->guard($this->getImpersonatorGuardName())->quietLogin($impersonator);
141
142
            $this->extractAuthCookieFromSession();
143
144
            $this->clear();
145
146
        } catch (\Exception $e) {
147
            unset($e);
148
            return false;
149
        }
150
151
        $this->app['events']->dispatch(new LeaveImpersonation($impersonator, $impersonated));
152
153
        return true;
154
    }
155
156
    public function clear()
157
    {
158
        session()->forget($this->getSessionKey());
159
        session()->forget($this->getSessionGuard());
160
        session()->forget($this->getSessionGuardUsing());
161
    }
162
163
    public function getSessionKey(): string
164
    {
165
        return config('laravel-impersonate.session_key');
166
    }
167
168
    public function getSessionGuard(): string
169
    {
170
        return config('laravel-impersonate.session_guard');
171
    }
172
173
    public function getSessionGuardUsing(): string
174
    {
175
        return config('laravel-impersonate.session_guard_using');
176
    }
177
178
    public function getDefaultSessionGuard(): string
179
    {
180
        return config('laravel-impersonate.default_impersonator_guard');
181
    }
182
183
    public function getTakeRedirectTo(): string
184
    {
185
        try {
186
            $uri = route(config('laravel-impersonate.take_redirect_to'));
187
        } catch (\InvalidArgumentException $e) {
188
            $uri = config('laravel-impersonate.take_redirect_to');
189
        }
190
191
        return $uri;
192
    }
193
194
    public function getLeaveRedirectTo(): string
195
    {
196
        try {
197
            $uri = route(config('laravel-impersonate.leave_redirect_to'));
198
        } catch (\InvalidArgumentException $e) {
199
            $uri = config('laravel-impersonate.leave_redirect_to');
200
        }
201
202
        return $uri;
203
    }
204
205
    /**
206
     * @return array|null
207
     */
208
    public function getCurrentAuthGuardName()
209
    {
210
        $guards = array_keys(config('auth.guards'));
211
212
        foreach ($guards as $guard) {
213
            if ($this->app['auth']->guard($guard)->check()) {
214
                return $guard;
215
            }
216
        }
217
218
        return null;
219
    }
220
221
    protected function saveAuthCookieInSession(): void
222
    {
223
        $cookie = $this->findByKeyInArray($this->app['request']->cookies->all(), static::REMEMBER_PREFIX);
224
        $key = $cookie->keys()->first();
225
        $val = $cookie->values()->first();
226
227
        if (!$key || !$val) {
228
            return;
229
        }
230
231
        session()->put(static::REMEMBER_PREFIX, [
232
            $key,
233
            $val,
234
        ]);
235
    }
236
237
    protected function extractAuthCookieFromSession(): void
238
    {
239
        if (!$session = $this->findByKeyInArray(session()->all(), static::REMEMBER_PREFIX)->first()) {
240
            return;
241
        }
242
243
        $this->app['cookie']->queue($session[0], $session[1]);
244
        session()->forget($session);
245
    }
246
247
    /**
248
     * @param array  $values
249
     * @param string $search
250
     * @return \Illuminate\Support\Collection
251
     */
252
    protected function findByKeyInArray(array $values, string $search)
253
    {
254
        return collect($values ?? session()->all())
255
            ->filter(function ($val, $key) use ($search) {
256
                return strpos($key, $search) !== false;
257
            });
258
    }
259
}
260