Passed
Branch master (acb862)
by Simon
03:16
created

HaveIBeenPwnedService   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 157
rs 10
c 0
b 0
f 0
wmc 12

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkList() 0 14 3
A getArgs() 0 3 1
A checkBreaches() 0 18 4
A checkPwndPassword() 0 17 1
A setArgs() 0 3 1
A __construct() 0 3 1
A checkPwndEmail() 0 17 1
1
<?php
2
3
namespace Firesphere\HaveIBeenPwned\Services;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\GuzzleException;
7
use Psr\Http\Message\ResponseInterface;
8
use SilverStripe\Core\Config\Configurable;
9
use SilverStripe\Core\Convert;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\Security\Member;
12
13
/**
14
 * Class HaveIBeenPwnedService
15
 * @package Firesphere\HaveIBeenPwned\Services
16
 */
17
class HaveIBeenPwnedService
18
{
19
    use Configurable;
20
21
    /**
22
     * Api endpoint emails
23
     */
24
    const PWND_URL = 'https://haveibeenpwned.com/api/';
25
26
    /**
27
     * API endpoint passwords
28
     */
29
    const PWND_API_URL = 'https://api.pwnedpasswords.com/';
30
31
    /**
32
     * API Version
33
     */
34
    const API_VERSION = '2';
35
36
    /**
37
     * Useragent
38
     */
39
    const USER_AGENT = 'Firesphere-HaveIBeenPwned-checker/1.0';
40
41
    /**
42
     * @config
43
     * @var bool
44
     */
45
    private static $allow_pwnd = false;
46
47
    /**
48
     * @config
49
     * @var bool
50
     */
51
    private static $save_pwnd = true;
52
53
    /**
54
     * @var array
55
     */
56
    protected $args;
57
58
    /**
59
     * HaveIBeenPwnedService constructor.
60
     * @param array $args
61
     */
62
    public function __construct($args = [])
63
    {
64
        $this->args = $args;
65
    }
66
67
    /**
68
     * @param string $pwd
69
     * @return int
70
     * @throws GuzzleException
71
     */
72
    public function checkPwndPassword($pwd)
73
    {
74
        $this->args['base_uri'] = static::PWND_API_URL;
75
76
        $sha = sha1($pwd);
77
        $shaStart = substr($sha, 0, 5);
78
        $shaEnd = substr($sha, 5);
79
        /** @var Client $client */
80
        $client = Injector::inst()->createWithArgs(Client::class, [$this->args]);
81
        $result = $client->request('GET', 'range/' . $shaStart, [
82
            'headers' => [
83
                'user-agent'  => static::USER_AGENT,
84
                'api-version' => static::API_VERSION
85
            ]
86
        ]);
87
88
        return $this->checkList($result, $shaEnd);
89
    }
90
91
    /**
92
     * @param ResponseInterface $result
93
     * @param $shaEnd
94
     * @return int
95
     */
96
    private function checkList($result, $shaEnd)
97
    {
98
        $count = 0;
99
        $shaEnd = strtoupper($shaEnd);
100
        $suffixes = explode("\n", $result->getBody());
101
        foreach ($suffixes as $suffix) {
102
            list($suffix, $pwnCount) = explode(':', trim($suffix));
103
            if ($suffix === $shaEnd) {
104
                $count += (int)$pwnCount;
105
                break;
106
            }
107
        }
108
109
        return $count;
110
    }
111
112
    /**
113
     * @param Member $member
114
     * @return string
115
     * @throws GuzzleException
116
     */
117
    public function checkPwndEmail($member)
118
    {
119
        $this->args['base_uri'] = static::PWND_URL;
120
        $uniqueField = Member::config()->get('unique_identifier_field');
121
        $account = $member->{$uniqueField};
122
123
        /** @var Client $client */
124
        $client = Injector::inst()->createWithArgs(Client::class, [$this->args]);
125
126
        $result = $client->request('GET', 'breachedaccount/' . $account . '?truncateResponse=true', [
127
            'headers' => [
128
                'user-agent'  => static::USER_AGENT,
129
                'api-version' => static::API_VERSION
130
            ]
131
        ]);
132
133
        return $this->checkBreaches($result);
134
    }
135
136
    /**
137
     * @param ResponseInterface $result
138
     * @return string
139
     */
140
    private function checkBreaches($result)
141
    {
142
        $body = $result->getBody();
143
144
        $sites = [];
145
146
        $breaches = Convert::json2array($body);
147
        foreach ($breaches as $breach) {
148
            if (!empty($breach['Name'])) {
149
                $sites[] = $breach['Name'];
150
            }
151
        }
152
153
        if (count($sites)) {
154
            return implode(', ', $sites);
155
        }
156
157
        return '';
158
    }
159
160
    /**
161
     * @return array
162
     */
163
    public function getArgs()
164
    {
165
        return $this->args;
166
    }
167
168
    /**
169
     * @param array $args
170
     */
171
    public function setArgs($args)
172
    {
173
        $this->args = $args;
174
    }
175
}
176