ImportsUsers::createDecryptionKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
namespace Slides\Connector\Auth\Sync;
4
5
use Illuminate\Encryption\Encrypter;
6
use Illuminate\Support\Arr;
7
8
/**
9
 * Trait ImportsUsers
10
 *
11
 * @package Slides\Connector\Auth\Sync
12
 */
13
trait ImportsUsers
14
{
15
    /**
16
     * The import dump headers.
17
     *
18
     * @var array
19
     */
20
    protected $importHeaders;
21
22
    /**
23
     * Export local users to a file in the compressed GZIP format.
24
     *
25
     * @param string $path
26
     * @param string $sharedKey
27
     * @param bool $importModes Whether import modes from the dump.
28
     *
29
     * @return void
30
     */
31
    public function import(string $path, string $sharedKey, bool $importModes = true)
32
    {
33
        $difference = $this->parseDump($path, $sharedKey, $importModes);
34
35
        $foreigners = array_map(function (array $user) {
36
            return $this->createRemoteUserFromResponse($user);
0 ignored issues
show
Bug introduced by
It seems like createRemoteUserFromResponse() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

36
            return $this->/** @scrutinizer ignore-call */ createRemoteUserFromResponse($user);
Loading history...
37
        }, $difference);
38
39
        $this->foreigners = collect($foreigners);
0 ignored issues
show
Bug Best Practice introduced by
The property foreigners does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
40
    }
41
42
    /**
43
     * Parse a dump and retrieve user entities in array representation.
44
     *
45
     * Steps:
46
     * 1. Read a file contents
47
     * 2. Decrypt using shared token and tenant credentials
48
     * 3. Decompress and decode from JSON to array
49
     *
50
     * @param string $filename
51
     * @param string $sharedKey
52
     * @param bool $importModes Whether import modes from the dump.
53
     *
54
     * @return array
55
     */
56
    private function parseDump(string $filename, string $sharedKey, bool $importModes): array
57
    {
58
        if(!file_exists($filename)) {
59
            throw new \InvalidArgumentException($filename . ' cannot be found');
60
        }
61
62
        // Retrieve dump contents, it's encrypted and gzipped
63
        // We should handle it firstly
64
        $payload = file_get_contents($filename);
65
66
        // Extract and parse headers which contain necessary information
67
        // Then delete from a dump so we can proceed with decryption
68
        $this->extractHeaders($payload);
69
70
        if($importModes) {
71
            $this->modes = Arr::get($this->importHeaders, 'modes', []);
0 ignored issues
show
Bug Best Practice introduced by
The property modes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
72
        }
73
74
        $encrypter = new Encrypter(
75
            $this->createDecryptionKey($sharedKey),
76
            $this->cipher
77
        );
78
79
        // Decrypt a payload. If successful, we retrieve compressed user entities
80
        $data = $encrypter->decrypt($payload);
81
82
        // Decompress users
83
        $data = gzdecode($data);
84
85
        return json_decode($data, true);
86
    }
87
88
    /**
89
     * Create a decryption key based on shared key and signature which authorizes tenant.
90
     *
91
     * @param string $sharedKey
92
     *
93
     * @return string
94
     */
95
    private function createDecryptionKey(string $sharedKey): string
96
    {
97
        return base64_decode($sharedKey) . ':' . $this->signature();
98
    }
99
100
    /**
101
     * Create a signature based on credentials.
102
     *
103
     * @return string
104
     */
105
    private function signature(): string
106
    {
107
        $sign = hash('sha256', $this->credential('public') . $this->credential('secret'));
0 ignored issues
show
Bug introduced by
It seems like credential() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
        $sign = hash('sha256', $this->/** @scrutinizer ignore-call */ credential('public') . $this->credential('secret'));
Loading history...
108
109
        return substr($sign, 0, 15);
110
    }
111
112
    /**
113
     * Extract and parse headers from the dump.
114
     *
115
     * @param string $payload
116
     *
117
     * @return array
118
     */
119
    private function extractHeaders(string &$payload): array
120
    {
121
        $headers = unserialize(
122
            base64_decode(strtok($payload, '/'))
123
        );
124
125
        // Remove header string from the payload
126
        $payload = ltrim(strstr($payload, '/'), '/');
127
128
        return $this->importHeaders = $headers;
129
    }
130
}