Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
Security
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
12 / 12
18
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 setUserPassword
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUserPassword
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasUserPassword
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setOwnerPassword
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getOwnerPassword
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasOwnerPassword
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setAlgorithm
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getAlgorithm
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPermissions
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getPermissions
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getEffectiveOwnerPassword
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Pdf\Document;
16
17/**
18 * Pdf security class
19 *
20 * @category   Pop
21 * @package    Pop\Pdf
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    6.2.0
26 */
27class Security
28{
29
30    /**
31     * Supported encryption algorithms
32     */
33    const AES_128 = 'AES128';
34    const AES_256 = 'AES256';
35
36    /**
37     * PDF user (open) password
38     * @var ?string
39     */
40    protected ?string $userPassword = null;
41
42    /**
43     * PDF owner (permissions) password
44     * @var ?string
45     */
46    protected ?string $ownerPassword = null;
47
48    /**
49     * Encryption algorithm, one of the AES_128/AES_256 constants
50     * @var string
51     */
52    protected string $algorithm = self::AES_256;
53
54    /**
55     * PDF permission flags
56     * @var ?Permissions
57     */
58    protected ?Permissions $permissions = null;
59
60    /**
61     * Randomly-generated owner password, used when the caller never sets one
62     * @var ?string
63     */
64    protected ?string $generatedOwnerPassword = null;
65
66    /**
67     * Instantiate the security object
68     *
69     * @param  ?string      $userPassword
70     * @param  ?string      $ownerPassword
71     * @param  ?Permissions $permissions
72     * @param  string       $algorithm
73     */
74    public function __construct(
75        ?string $userPassword = null, ?string $ownerPassword = null,
76        ?Permissions $permissions = null, string $algorithm = self::AES_256
77    )
78    {
79        if ($userPassword !== null) {
80            $this->setUserPassword($userPassword);
81        }
82        if ($ownerPassword !== null) {
83            $this->setOwnerPassword($ownerPassword);
84        }
85        if ($permissions !== null) {
86            $this->setPermissions($permissions);
87        }
88        $this->setAlgorithm($algorithm);
89    }
90
91    /**
92     * Set the user (open) password
93     *
94     * @param  ?string $password
95     * @return Security
96     */
97    public function setUserPassword(?string $password): Security
98    {
99        $this->userPassword = $password;
100        return $this;
101    }
102
103    /**
104     * Get the user (open) password
105     *
106     * @return ?string
107     */
108    public function getUserPassword(): ?string
109    {
110        return $this->userPassword;
111    }
112
113    /**
114     * Determine whether a user (open) password has been set
115     *
116     * @return bool
117     */
118    public function hasUserPassword(): bool
119    {
120        return ($this->userPassword !== null);
121    }
122
123    /**
124     * Set the owner (permissions) password
125     *
126     * @param  ?string $password
127     * @return Security
128     */
129    public function setOwnerPassword(?string $password): Security
130    {
131        $this->ownerPassword = $password;
132        return $this;
133    }
134
135    /**
136     * Get the owner (permissions) password
137     *
138     * @return ?string
139     */
140    public function getOwnerPassword(): ?string
141    {
142        return $this->ownerPassword;
143    }
144
145    /**
146     * Determine whether an owner (permissions) password has been set
147     *
148     * @return bool
149     */
150    public function hasOwnerPassword(): bool
151    {
152        return ($this->ownerPassword !== null);
153    }
154
155    /**
156     * Set the encryption algorithm
157     *
158     * @param  string $algorithm
159     * @return Security
160     */
161    public function setAlgorithm(string $algorithm): Security
162    {
163        $this->algorithm = $algorithm;
164        return $this;
165    }
166
167    /**
168     * Get the encryption algorithm
169     *
170     * @return string
171     */
172    public function getAlgorithm(): string
173    {
174        return $this->algorithm;
175    }
176
177    /**
178     * Set the permission flags
179     *
180     * @param  Permissions $permissions
181     * @return Security
182     */
183    public function setPermissions(Permissions $permissions): Security
184    {
185        $this->permissions = $permissions;
186        return $this;
187    }
188
189    /**
190     * Get the permission flags, creating a default all-allowed set if none was configured
191     *
192     * @return Permissions
193     */
194    public function getPermissions(): Permissions
195    {
196        if ($this->permissions === null) {
197            $this->permissions = new Permissions();
198        }
199        return $this->permissions;
200    }
201
202    /**
203     * The password actually used as the PDF Owner password when computing
204     * /O, /U, etc. If the caller never set one, a random password is
205     * generated once and cached here - leaving it truly blank would mean
206     * anyone could remove restrictions with an empty owner password,
207     * silently defeating the permissions feature.
208     *
209     * @return string
210     */
211    public function getEffectiveOwnerPassword(): string
212    {
213        if ($this->hasOwnerPassword()) {
214            return $this->ownerPassword;
215        }
216
217        if ($this->generatedOwnerPassword === null) {
218            $this->generatedOwnerPassword = base64_encode(random_bytes(24));
219        }
220
221        return $this->generatedOwnerPassword;
222    }
223}