Completed
Push — master ( cbed4d...29d6d4 )
by Felix
02:53
created

PhPsst   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 7
Bugs 0 Features 2
Metric Value
wmc 14
c 7
b 0
f 2
lcom 1
cbo 4
dl 0
loc 110
ccs 48
cts 48
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
B store() 0 24 4
A __construct() 0 9 2
B retrieve() 0 22 5
A generateKey() 0 16 3
1
<?php
2
/**
3
 * PhPsst.
4
 *
5
 * @copyright Copyright (c) 2016 Felix Sandström
6
 * @license   MIT
7
 */
8
9
namespace PhPsst;
10
11
use Illuminate\Encryption\Encrypter;
12
use PhPsst\Storage\Storage;
13
14
/**
15
 * A PHP library for distributing (one time) passwords/secrets in a more secure way.
16
 *
17
 * @author Felix Sandström <http://github.com/felixsand>
18
 */
19
class PhPsst
20
{
21
    /**
22
     * @var Storage
23
     */
24
    protected $storage;
25
26
    /**
27
     * @var string
28
     */
29
    protected $cipher;
30
31
    /**
32
     * @const string
33
     */
34
    const CIPHER_DEFAULT = 'AES-256-CBC';
35
36
    /**
37
     * PhPsst constructor.
38
     * @param Storage $storage
39
     * @param string $cipher
40
     */
41 5
    public function __construct(Storage $storage, $cipher = null)
42
    {
43 5
        $this->storage = $storage;
44 5
        if ($cipher !== null) {
45 1
            $this->cipher = $cipher;
46 1
        } else {
47 5
            $this->cipher = self::CIPHER_DEFAULT;
48
        }
49 5
    }
50
51
    /**
52
     * @param string $password
53
     * @param int $ttl
54
     * @param int $views
55
     * @return string
56
     */
57 9
    public function store($password, $ttl = 3600, $views = 1)
58
    {
59 9
        if (empty($password)) {
60 1
            throw new \InvalidArgumentException('The password has to be set');
61
        }
62
63 8
        $ttl = (int) $ttl;
64 8
        if ($ttl < 1) {
65 1
            throw new \InvalidArgumentException('TTL has to be higher than 0');
66
        }
67
68 7
        $views = (int) $views;
69 7
        if ($views < 1) {
70 1
            throw new \InvalidArgumentException('Views has to be highter han 0');
71
        }
72
73 6
        $id = uniqid();
74 6
        $key = $this->generateKey();
75 5
        $encrypter = new Encrypter($key, $this->cipher);
76
77 5
        $this->storage->store(new Password($id, $encrypter->encrypt($password), $ttl, $views));
78
79 5
        return $id . ';' . $key;
80
    }
81
82
    /**
83
     * @param $secret
84
     * @return string
85
     */
86 6
    public function retrieve($secret)
87
    {
88 6
        if (!($idKeyArray = explode(';', $secret)) || count($idKeyArray) != 2) {
89 1
            throw new \InvalidArgumentException('Invalid secret');
90
        }
91 5
        list($id, $key) = $idKeyArray;
92 5
        $id = preg_replace("/[^a-zA-Z\d]/", '', $id);
93
94 5
        if (!($password = $this->storage->get($id))) {
95 3
            throw new PhPsstException('No password with that ID found', PhPsstException::NO_PASSWORD_WITH_ID_FOUND);
96
        }
97 4
        $encrypter = new Encrypter($key, $this->cipher);
98
99 4
        $password->decreaseViews();
100 4
        if ($password->getViews() > 0) {
101 2
            $this->storage->store($password, true);
102 2
        } else {
103 2
            $this->storage->delete($password);
104
        }
105
106 4
        return $encrypter->decrypt($password->getPassword());
107
    }
108
109
    /**
110
     * @return string
111
     */
112 3
    protected function generateKey()
113
    {
114 3
        $key = null;
0 ignored issues
show
Unused Code introduced by
$key is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
115 3
        switch ($this->cipher) {
116 3
            case 'AES-128-CBC':
117 1
                $key = bin2hex(random_bytes(8));
118 1
                break;
119 2
            case 'AES-256-CBC':
120 1
                $key = bin2hex(random_bytes(16));
121 1
                break;
122 1
            default:
123 1
                throw new \RuntimeException('Only supported ciphers are AES-128-CBC and AES-256-CBC');
124 3
        }
125
126 2
        return $key;
127
    }
128
}
129