These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * PrivateBin |
||
4 | * |
||
5 | * a zero-knowledge paste bin |
||
6 | * |
||
7 | * @link https://github.com/PrivateBin/PrivateBin |
||
8 | * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) |
||
9 | * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License |
||
10 | * @version 1.1 |
||
11 | */ |
||
12 | |||
13 | namespace PrivateBin\Model; |
||
14 | |||
15 | use Exception; |
||
16 | use PrivateBin\Persistence\ServerSalt; |
||
17 | use PrivateBin\PrivateBin; |
||
18 | use PrivateBin\Sjcl; |
||
19 | |||
20 | /** |
||
21 | * Paste |
||
22 | * |
||
23 | * Model of a PrivateBin paste. |
||
24 | */ |
||
25 | class Paste extends AbstractModel |
||
26 | { |
||
27 | /** |
||
28 | * Get paste data. |
||
29 | * |
||
30 | * @access public |
||
31 | * @throws Exception |
||
32 | * @return stdClass |
||
33 | */ |
||
34 | 38 | public function get() |
|
35 | { |
||
36 | 38 | $data = $this->_store->read($this->getId()); |
|
37 | 38 | if ($data === false) { |
|
38 | 1 | throw new Exception(PrivateBin::GENERIC_ERROR, 64); |
|
39 | } |
||
40 | |||
41 | // check if paste has expired and delete it if neccessary. |
||
42 | 37 | if (property_exists($data->meta, 'expire_date')) { |
|
43 | 5 | if ($data->meta->expire_date < time()) { |
|
44 | 4 | $this->delete(); |
|
45 | 4 | throw new Exception(PrivateBin::GENERIC_ERROR, 63); |
|
46 | } |
||
47 | // We kindly provide the remaining time before expiration (in seconds) |
||
48 | 1 | $data->meta->remaining_time = $data->meta->expire_date - time(); |
|
49 | } |
||
50 | |||
51 | // set formatter for for the view. |
||
52 | 33 | if (!property_exists($data->meta, 'formatter')) { |
|
53 | // support < 0.21 syntax highlighting |
||
54 | 6 | if (property_exists($data->meta, 'syntaxcoloring') && $data->meta->syntaxcoloring === true) { |
|
55 | 2 | $data->meta->formatter = 'syntaxhighlighting'; |
|
56 | } else { |
||
57 | 4 | $data->meta->formatter = $this->_conf->getKey('defaultformatter'); |
|
58 | } |
||
59 | } |
||
60 | |||
61 | // support old paste format with server wide salt |
||
62 | 33 | if (!property_exists($data->meta, 'salt')) { |
|
63 | 4 | $data->meta->salt = ServerSalt::get(); |
|
64 | } |
||
65 | 33 | $data->comments = array_values($this->getComments()); |
|
66 | 33 | $data->comment_count = count($data->comments); |
|
67 | 33 | $data->comment_offset = 0; |
|
68 | 33 | $data->{'@context'} = 'js/paste.jsonld'; |
|
69 | 33 | $this->_data = $data; |
|
70 | 33 | return $this->_data; |
|
71 | } |
||
72 | |||
73 | /** |
||
74 | * Store the paste's data. |
||
75 | * |
||
76 | * @access public |
||
77 | * @throws Exception |
||
78 | */ |
||
79 | 35 | public function store() |
|
80 | { |
||
81 | // Check for improbable collision. |
||
82 | 35 | if ($this->exists()) { |
|
83 | 3 | throw new Exception('You are unlucky. Try again.', 75); |
|
84 | } |
||
85 | |||
86 | 33 | $this->_data->meta->postdate = time(); |
|
87 | 33 | $this->_data->meta->salt = serversalt::generate(); |
|
88 | |||
89 | // store paste |
||
90 | if ( |
||
0 ignored issues
–
show
|
|||
91 | 33 | $this->_store->create( |
|
92 | 33 | $this->getId(), |
|
93 | 33 | json_decode(json_encode($this->_data), true) |
|
94 | 33 | ) === false |
|
95 | ) { |
||
96 | throw new Exception('Error saving paste. Sorry.', 76); |
||
97 | } |
||
98 | 33 | } |
|
99 | |||
100 | /** |
||
101 | * Delete the paste. |
||
102 | * |
||
103 | * @access public |
||
104 | * @throws Exception |
||
105 | */ |
||
106 | 24 | public function delete() |
|
107 | { |
||
108 | 24 | $this->_store->delete($this->getId()); |
|
109 | 24 | } |
|
110 | |||
111 | /** |
||
112 | * Test if paste exists in store. |
||
113 | * |
||
114 | * @access public |
||
115 | * @return bool |
||
116 | */ |
||
117 | 82 | public function exists() |
|
118 | { |
||
119 | 82 | return $this->_store->exists($this->getId()); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Get a comment, optionally a specific instance. |
||
124 | * |
||
125 | * @access public |
||
126 | * @param string $parentId |
||
127 | * @param string $commentId |
||
128 | * @throws Exception |
||
129 | * @return Comment |
||
130 | */ |
||
131 | 20 | public function getComment($parentId, $commentId = null) |
|
132 | { |
||
133 | 20 | if (!$this->exists()) { |
|
134 | 1 | throw new Exception('Invalid data.', 62); |
|
135 | } |
||
136 | 19 | $comment = new Comment($this->_conf, $this->_store); |
|
137 | 19 | $comment->setPaste($this); |
|
138 | 19 | $comment->setParentId($parentId); |
|
139 | 17 | if ($commentId !== null) { |
|
140 | 5 | $comment->setId($commentId); |
|
141 | } |
||
142 | 17 | return $comment; |
|
143 | } |
||
144 | |||
145 | /** |
||
146 | * Get all comments, if any. |
||
147 | * |
||
148 | * @access public |
||
149 | * @return array |
||
150 | */ |
||
151 | 33 | public function getComments() |
|
152 | { |
||
153 | 33 | return $this->_store->readComments($this->getId()); |
|
154 | } |
||
155 | |||
156 | /** |
||
157 | * Generate the "delete" token. |
||
158 | * |
||
159 | * The token is the hmac of the pastes ID signed with the server salt. |
||
160 | * The paste can be deleted by calling: |
||
161 | * http://example.com/privatebin/?pasteid=<pasteid>&deletetoken=<deletetoken> |
||
162 | * |
||
163 | * @access public |
||
164 | * @return string |
||
165 | */ |
||
166 | 32 | public function getDeleteToken() |
|
167 | { |
||
168 | 32 | if (!property_exists($this->_data->meta, 'salt')) { |
|
169 | $this->get(); |
||
170 | } |
||
171 | 32 | return hash_hmac( |
|
172 | 32 | $this->_conf->getKey('zerobincompatibility') ? 'sha1' : 'sha256', |
|
173 | 32 | $this->getId(), |
|
174 | 32 | $this->_data->meta->salt |
|
175 | ); |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Set paste's attachment. |
||
180 | * |
||
181 | * @access public |
||
182 | * @param string $attachment |
||
183 | * @throws Exception |
||
184 | */ |
||
185 | 2 | View Code Duplication | public function setAttachment($attachment) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
186 | { |
||
187 | 2 | if (!$this->_conf->getKey('fileupload') || !Sjcl::isValid($attachment)) { |
|
188 | throw new Exception('Invalid attachment.', 71); |
||
189 | } |
||
190 | 2 | $this->_data->meta->attachment = $attachment; |
|
191 | 2 | } |
|
192 | |||
193 | /** |
||
194 | * Set paste's attachment name. |
||
195 | * |
||
196 | * @access public |
||
197 | * @param string $attachmentname |
||
198 | * @throws Exception |
||
199 | */ |
||
200 | 2 | View Code Duplication | public function setAttachmentName($attachmentname) |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
201 | { |
||
202 | 2 | if (!$this->_conf->getKey('fileupload') || !Sjcl::isValid($attachmentname)) { |
|
203 | throw new Exception('Invalid attachment.', 72); |
||
204 | } |
||
205 | 2 | $this->_data->meta->attachmentname = $attachmentname; |
|
206 | 2 | } |
|
207 | |||
208 | /** |
||
209 | * Set paste expiration. |
||
210 | * |
||
211 | * @access public |
||
212 | * @param string $expiration |
||
213 | */ |
||
214 | 7 | public function setExpiration($expiration) |
|
215 | { |
||
216 | 7 | $expire_options = $this->_conf->getSection('expire_options'); |
|
217 | 7 | if (array_key_exists($expiration, $expire_options)) { |
|
218 | 5 | $expire = $expire_options[$expiration]; |
|
219 | } else { |
||
220 | // using getKey() to ensure a default value is present |
||
221 | 2 | $expire = $this->_conf->getKey($this->_conf->getKey('default', 'expire'), 'expire_options'); |
|
222 | } |
||
223 | 7 | if ($expire > 0) { |
|
224 | 7 | $this->_data->meta->expire_date = time() + $expire; |
|
225 | } |
||
226 | 7 | } |
|
227 | |||
228 | /** |
||
229 | * Set paste's burn-after-reading type. |
||
230 | * |
||
231 | * @access public |
||
232 | * @param string $burnafterreading |
||
233 | * @throws Exception |
||
234 | */ |
||
235 | 3 | public function setBurnafterreading($burnafterreading = '1') |
|
236 | { |
||
237 | 3 | if ($burnafterreading === '0') { |
|
238 | 1 | $this->_data->meta->burnafterreading = false; |
|
239 | } else { |
||
240 | 3 | if ($burnafterreading !== '1') { |
|
241 | 2 | throw new Exception('Invalid data.', 73); |
|
242 | } |
||
243 | 1 | $this->_data->meta->burnafterreading = true; |
|
244 | 1 | $this->_data->meta->opendiscussion = false; |
|
245 | } |
||
246 | 1 | } |
|
247 | |||
248 | /** |
||
249 | * Set paste's discussion state. |
||
250 | * |
||
251 | * @access public |
||
252 | * @param string $opendiscussion |
||
253 | * @throws Exception |
||
254 | */ |
||
255 | 11 | public function setOpendiscussion($opendiscussion = '1') |
|
256 | { |
||
257 | if ( |
||
258 | 11 | !$this->_conf->getKey('discussion') || |
|
259 | 11 | $this->isBurnafterreading() || |
|
260 | 11 | $opendiscussion === '0' |
|
261 | ) { |
||
262 | 1 | $this->_data->meta->opendiscussion = false; |
|
263 | } else { |
||
264 | 11 | if ($opendiscussion !== '1') { |
|
265 | 2 | throw new Exception('Invalid data.', 74); |
|
266 | } |
||
267 | 9 | $this->_data->meta->opendiscussion = true; |
|
268 | } |
||
269 | 9 | } |
|
270 | |||
271 | /** |
||
272 | * Set paste's format. |
||
273 | * |
||
274 | * @access public |
||
275 | * @param string $format |
||
276 | * @throws Exception |
||
277 | */ |
||
278 | 8 | public function setFormatter($format) |
|
279 | { |
||
280 | 8 | if (!array_key_exists($format, $this->_conf->getSection('formatter_options'))) { |
|
281 | 2 | $format = $this->_conf->getKey('defaultformatter'); |
|
282 | } |
||
283 | 8 | $this->_data->meta->formatter = $format; |
|
284 | 8 | } |
|
285 | |||
286 | /** |
||
287 | * Check if paste is of burn-after-reading type. |
||
288 | * |
||
289 | * @access public |
||
290 | * @throws Exception |
||
291 | * @return bool |
||
292 | */ |
||
293 | 25 | View Code Duplication | public function isBurnafterreading() |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
294 | { |
||
295 | 25 | if (!property_exists($this->_data, 'data')) { |
|
296 | 14 | $this->get(); |
|
297 | } |
||
298 | 23 | return property_exists($this->_data->meta, 'burnafterreading') && |
|
299 | 23 | $this->_data->meta->burnafterreading === true; |
|
300 | } |
||
301 | |||
302 | /** |
||
303 | * Check if paste has discussions enabled. |
||
304 | * |
||
305 | * @access public |
||
306 | * @throws Exception |
||
307 | * @return bool |
||
308 | */ |
||
309 | 13 | View Code Duplication | public function isOpendiscussion() |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
310 | { |
||
311 | 13 | if (!property_exists($this->_data, 'data')) { |
|
312 | 8 | $this->get(); |
|
313 | } |
||
314 | 13 | return property_exists($this->_data->meta, 'opendiscussion') && |
|
315 | 13 | $this->_data->meta->opendiscussion === true; |
|
316 | } |
||
317 | } |
||
318 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.