Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.37% covered (success)
97.37%
37 / 38
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
get_updates
97.37% covered (success)
97.37%
37 / 38
80.00% covered (warning)
80.00%
4 / 5
16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 download
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 validate
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
9.02
 extract
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 copy
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\update;
15
16use GuzzleHttp\Client;
17use GuzzleHttp\Exception\GuzzleException;
18use phpbb\filesystem\exception\filesystem_exception;
19use phpbb\filesystem\filesystem_interface;
20use SodiumException;
21use ZipArchive;
22
23class get_updates
24{
25    /** @var filesystem_interface Filesystem manager */
26    protected filesystem_interface $filesystem;
27
28    /** @var Client HTTP client */
29    protected Client $http_client;
30
31    /** @var ZipArchive Zip extractor */
32    protected ZipArchive $zipper;
33
34    /** @var string Public key to verify package  */
35    protected string $public_key;
36
37    /** @var string phpBB root path */
38    private string $phpbb_root_path;
39
40    /**
41     * Constructor
42     *
43     * @param filesystem_interface $filesystem
44     * @param string $public_key
45     * @param string $phpbb_root_path
46     */
47    public function __construct(
48        filesystem_interface $filesystem,
49        string $public_key,
50        string $phpbb_root_path)
51    {
52        $this->filesystem = $filesystem;
53        $this->http_client = new Client();
54        $this->zipper = new ZipArchive();
55        $this->public_key = base64_decode($public_key);
56        $this->phpbb_root_path = $phpbb_root_path;
57    }
58
59    /**
60     * Download the update package.
61     *
62     * @param string $url            Download link to the update.
63     * @param string $storage_path    Location for the download.
64     *
65     * @return bool Whether the download completed successfully.
66     */
67    public function download(string $url, string $storage_path): bool
68    {
69        try
70        {
71            $this->http_client->request('GET', $url, [
72                'sink' => $storage_path,
73                'allow_redirects' => false
74            ]);
75        }
76        catch (GuzzleException)
77        {
78            return false;
79        }
80
81        return true;
82    }
83
84    /**
85     * Validate the downloaded file.
86     *
87     * @param string $file_path            Path to the download.
88     * @param string $signature_path    The signature file.
89     *
90     * @return bool Whether the signature is correct or not.
91     */
92    public function validate(string $file_path, string $signature_path): bool
93    {
94        if (file_exists($file_path) === false || !is_readable($file_path))
95        {
96            return false;
97        }
98
99        if (file_exists($signature_path) === false || !is_readable($signature_path))
100        {
101            return false;
102        }
103
104        $signature = file_get_contents($signature_path);
105
106        $hash = hash_file('sha384', $file_path, true);
107        if ($hash === false)
108        {
109            return false;
110        }
111
112        $raw_signature = base64_decode($signature, true);
113        if ($raw_signature === false)
114        {
115            return false;
116        }
117
118        $raw_public_key = base64_decode($this->public_key, true);
119        if ($raw_public_key === false)
120        {
121            return false;
122        }
123
124        try
125        {
126            return sodium_crypto_sign_verify_detached($raw_signature, $hash, $raw_public_key);
127        }
128        catch (SodiumException)
129        {
130            return false;
131        }
132    }
133
134    /**
135     * Extract the downloaded archive.
136     *
137     * @param string $zip_file    Path to the archive.
138     * @param string $to        Path to where to extract the archive to.
139     *
140     * @return bool Whether the extraction completed successfully.
141     */
142    public function extract(string $zip_file, string $to): bool
143    {
144        if ($this->zipper->open($zip_file) === false)
145        {
146            return false;
147        }
148
149        $result = $this->zipper->extractTo($to);
150        $this->zipper->close();
151
152        return $result;
153    }
154
155    /**
156     * Copy the update package to the root folder.
157     *
158     * @param string $src_dir Where to copy from.
159     *
160     * @return bool Whether the files were copied successfully.
161     */
162    public function copy(string $src_dir): bool
163    {
164        try
165        {
166            $this->filesystem->mirror($src_dir, $this->phpbb_root_path);
167        }
168        catch (filesystem_exception)
169        {
170            return false;
171        }
172
173        return true;
174    }
175}