GenerateJWTKeysCommand   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Test Coverage

Coverage 94.44%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 68
c 2
b 0
f 0
dl 0
loc 161
ccs 68
cts 72
cp 0.9444
rs 10
wmc 19

5 Methods

Rating   Name   Duplication   Size   Complexity  
A createPublicKeyFile() 0 23 2
B newFilesCanBeStored() 0 17 7
A createPrivateKeyFile() 0 26 2
A prepareDirectoryForFiles() 0 7 3
A handle() 0 29 5
1
<?php
2
3
4
namespace JWTAuth\Console;
5
6
use Illuminate\Console\Command;
7
use Illuminate\Support\Facades\File;
8
use Symfony\Component\Process\Process;
9
10
/**
11
 *
12
 * Example of manual creation:
13
 * cd storage/jwt-keys
14
 * ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
15
 * openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
16
 *
17
 * Class GenerateJWTKeysCommand
18
 * @package JWTAuth\Console
19
 */
20
class GenerateJWTKeysCommand extends Command
21
{
22
23
    /**
24
     * The name and signature of the console command.
25
     *
26
     * @var string
27
     */
28
    protected $signature = 'jwt:keys:generate
29
    {--key-dir=jwt-keys : Key directory}
30
    {--key-name=jwtRS256 : Key name}
31
    {--force : Force precess}
32
    ';
33
34
    /**
35
     * The console command description.
36
     *
37
     * @var string
38
     */
39
    protected $description = 'Generate JWT Keys';
40
41
    /**
42
     * Execute the console command.
43
     *
44
     * @return int
45
     */
46 8
    public function handle(): int
47
    {
48 8
        $directory = $this->option('key-dir');
49 8
        $keyName   = $this->option('key-name');
50
51 8
        if (!$this->option('force')) {
52 4
            $directory = $this->ask('Directory name where will be stored keys:', $directory);
53 4
            $keyName   = $this->ask('Key name:', $keyName);
54
        }
55
56 8
        $dirFullPath    = storage_path($directory);
57 8
        $privateKeyPath = storage_path("{$directory}/{$keyName}.key");
58 8
        $publicKeyPath  = storage_path("{$directory}/{$keyName}.key.pub");
59
60 8
        if (!$this->newFilesCanBeStored($privateKeyPath, $publicKeyPath)) {
61 1
            return 1;
62
        }
63
64 7
        $this->prepareDirectoryForFiles($dirFullPath);
65
66 7
        if (!$this->createPrivateKeyFile($privateKeyPath)) {
67 1
            return 2;
68
        }
69
70 6
        if (!$this->createPublicKeyFile($privateKeyPath, $publicKeyPath)) {
71
            return 3;
72
        }
73
74 6
        return 0;
75
    }
76
77
    /**
78
     * Create and store private key file.
79
     *
80
     * @param string $privateKeyPath
81
     *
82
     * @return bool
83
     */
84 7
    protected function createPrivateKeyFile(string $privateKeyPath): bool
85
    {
86 7
        $process = new Process([
87 7
            'ssh-keygen',
88 7
            '-t',
89 7
            'rsa',
90 7
            '-b',
91 7
            '4096',
92 7
            '-N',
93 7
            '',
94 7
            '-q',
95 7
            '-m',
96 7
            'PEM',
97 7
            '-f',
98 7
            $privateKeyPath,
99 7
        ]);
100 7
        $process->run();
101
102 7
        if (!$process->isSuccessful()) {
103 1
            $this->error($process->getErrorOutput());
104 1
            $this->error('Private key not created.');
105
106 1
            return false;
107
        }
108
109 6
        return true;
110
    }
111
112
    /**
113
     * Create and store public key file.
114
     *
115
     * @param string $privateKeyPath
116
     * @param string $publicKeyPath
117
     *
118
     * @return bool
119
     */
120 6
    protected function createPublicKeyFile(string $privateKeyPath, string $publicKeyPath): bool
121
    {
122 6
        $process = new Process([
123 6
            'openssl',
124 6
            'rsa',
125 6
            '-in',
126 6
            $privateKeyPath,
127 6
            '-pubout',
128 6
            '-outform',
129 6
            'PEM',
130 6
            '-out',
131 6
            $publicKeyPath,
132 6
        ]);
133 6
        $process->run();
134
135 6
        if (!$process->isSuccessful()) {
136
            $this->error($process->getErrorOutput());
137
            $this->error('Public key not converted.');
138
139
            return false;
140
        }
141
142 6
        return true;
143
    }
144
145
    /**
146
     * @param string $dirFullPath
147
     */
148 7
    protected function prepareDirectoryForFiles(string $dirFullPath)
149
    {
150 7
        if (!File::isDirectory($dirFullPath)) {
151 2
            File::makeDirectory($dirFullPath, 0755, true, true);
152
        }
153 7
        if (!File::exists("{$dirFullPath}/.gitignore")) {
154 3
            File::put("{$dirFullPath}/.gitignore", "*\n!.gitignore");
155
        }
156
    }
157
158
    /**
159
     * @param string $privateKeyPath
160
     * @param string $publicKeyPath
161
     *
162
     * @return bool
163
     */
164 8
    protected function newFilesCanBeStored(string $privateKeyPath, string $publicKeyPath): bool
165
    {
166 8
        if (File::exists($privateKeyPath) || File::exists($publicKeyPath)) {
167 5
            if (File::exists($privateKeyPath)) {
168 5
                $this->warn("File exists: {$privateKeyPath}");
169
            }
170 5
            if (File::exists($publicKeyPath)) {
171 5
                $this->warn("File exists: {$publicKeyPath}");
172
            }
173 5
            if (!$this->option('force') && !$this->confirm('Keys already exists. Do you wish to continue?')) {
174 1
                return false;
175
            }
176 4
            File::delete($privateKeyPath);
177 4
            File::delete($publicKeyPath);
178
        }
179
180 7
        return true;
181
    }
182
}
183