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 0.22 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace PrivateBin\Model; |
14
|
|
|
|
15
|
|
|
use PrivateBin\Sjcl; |
16
|
|
|
use PrivateBin\Persistence\TrafficLimiter; |
17
|
|
|
use PrivateBin\Vizhash16x16; |
18
|
|
|
use Identicon\Identicon; |
19
|
|
|
use Exception; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Comment |
23
|
|
|
* |
24
|
|
|
* Model of a PrivateBin comment. |
25
|
|
|
*/ |
26
|
|
|
class Comment extends AbstractModel |
27
|
|
|
{ |
28
|
|
|
/** |
29
|
|
|
* Instance's parent. |
30
|
|
|
* |
31
|
|
|
* @access private |
32
|
|
|
* @var Paste |
33
|
|
|
*/ |
34
|
|
|
private $_paste; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Get comment data. |
38
|
|
|
* |
39
|
|
|
* @access public |
40
|
|
|
* @throws Exception |
41
|
|
|
* @return stdClass |
42
|
|
|
*/ |
43
|
5 |
|
public function get() |
44
|
|
|
{ |
45
|
|
|
// @todo add support to read specific comment |
46
|
5 |
|
$comments = $this->_store->readComments($this->getPaste()->getId()); |
47
|
5 |
|
foreach ($comments as $comment) { |
48
|
|
|
if ( |
49
|
5 |
|
$comment->parentid == $this->getParentId() && |
50
|
5 |
|
$comment->id == $this->getId() |
51
|
|
|
) { |
52
|
5 |
|
$this->_data = $comment; |
53
|
5 |
|
break; |
54
|
|
|
} |
55
|
|
|
} |
56
|
5 |
|
return $this->_data; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Store the comment's data. |
61
|
|
|
* |
62
|
|
|
* @access public |
63
|
|
|
* @throws Exception |
64
|
|
|
* @return void |
65
|
|
|
*/ |
66
|
12 |
|
public function store() |
67
|
|
|
{ |
68
|
|
|
// Make sure paste exists. |
69
|
12 |
|
$pasteid = $this->getPaste()->getId(); |
70
|
12 |
|
if (!$this->getPaste()->exists()) { |
71
|
|
|
throw new Exception('Invalid data.', 67); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
// Make sure the discussion is opened in this paste and in configuration. |
75
|
12 |
|
if (!$this->getPaste()->isOpendiscussion() || !$this->_conf->getKey('discussion')) { |
76
|
2 |
|
throw new Exception('Invalid data.', 68); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
// Check for improbable collision. |
80
|
10 |
|
if ($this->exists()) { |
81
|
3 |
|
throw new Exception('You are unlucky. Try again.', 69); |
82
|
|
|
} |
83
|
|
|
|
84
|
8 |
|
$this->_data->meta->postdate = time(); |
85
|
|
|
|
86
|
|
|
// store comment |
87
|
|
|
if ( |
|
|
|
|
88
|
8 |
|
$this->_store->createComment( |
89
|
|
|
$pasteid, |
90
|
8 |
|
$this->getParentId(), |
91
|
8 |
|
$this->getId(), |
92
|
8 |
|
json_decode(json_encode($this->_data), true) |
93
|
8 |
|
) === false |
94
|
|
|
) { |
95
|
|
|
throw new Exception('Error saving comment. Sorry.', 70); |
96
|
|
|
} |
97
|
8 |
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Delete the comment. |
101
|
|
|
* |
102
|
|
|
* @access public |
103
|
|
|
* @throws Exception |
104
|
|
|
* @return void |
105
|
|
|
*/ |
106
|
1 |
|
public function delete() |
107
|
|
|
{ |
108
|
1 |
|
throw new Exception('To delete a comment, delete its parent paste', 64); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Test if comment exists in store. |
113
|
|
|
* |
114
|
|
|
* @access public |
115
|
|
|
* @return bool |
116
|
|
|
*/ |
117
|
10 |
|
public function exists() |
118
|
|
|
{ |
119
|
10 |
|
return $this->_store->existsComment( |
120
|
10 |
|
$this->getPaste()->getId(), |
121
|
10 |
|
$this->getParentId(), |
122
|
10 |
|
$this->getId() |
123
|
|
|
); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Set paste. |
128
|
|
|
* |
129
|
|
|
* @access public |
130
|
|
|
* @param Paste $paste |
131
|
|
|
* @throws Exception |
132
|
|
|
* @return void |
133
|
|
|
*/ |
134
|
17 |
|
public function setPaste(Paste $paste) |
135
|
|
|
{ |
136
|
17 |
|
$this->_paste = $paste; |
137
|
17 |
|
$this->_data->meta->pasteid = $paste->getId(); |
138
|
17 |
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Get paste. |
142
|
|
|
* |
143
|
|
|
* @access public |
144
|
|
|
* @return Paste |
145
|
|
|
*/ |
146
|
12 |
|
public function getPaste() |
147
|
|
|
{ |
148
|
12 |
|
return $this->_paste; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Set parent ID. |
153
|
|
|
* |
154
|
|
|
* @access public |
155
|
|
|
* @param string $id |
156
|
|
|
* @throws Exception |
157
|
|
|
* @return void |
158
|
|
|
*/ |
159
|
17 |
|
public function setParentId($id) |
160
|
|
|
{ |
161
|
17 |
|
if (!self::isValidId($id)) { |
162
|
2 |
|
throw new Exception('Invalid paste ID.', 65); |
163
|
|
|
} |
164
|
15 |
|
$this->_data->meta->parentid = $id; |
165
|
15 |
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Get parent ID. |
169
|
|
|
* |
170
|
|
|
* @access public |
171
|
|
|
* @return string |
172
|
|
|
*/ |
173
|
10 |
|
public function getParentId() |
174
|
|
|
{ |
175
|
10 |
|
if (!property_exists($this->_data->meta, 'parentid')) { |
176
|
|
|
$this->_data->meta->parentid = ''; |
177
|
|
|
} |
178
|
10 |
|
return $this->_data->meta->parentid; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Set nickname. |
183
|
|
|
* |
184
|
|
|
* @access public |
185
|
|
|
* @param string $nickname |
186
|
|
|
* @throws Exception |
187
|
|
|
* @return void |
188
|
|
|
*/ |
189
|
14 |
|
public function setNickname($nickname) |
190
|
|
|
{ |
191
|
14 |
|
if (!Sjcl::isValid($nickname)) { |
192
|
2 |
|
throw new Exception('Invalid data.', 66); |
193
|
|
|
} |
194
|
12 |
|
$this->_data->meta->nickname = $nickname; |
195
|
|
|
|
196
|
|
|
// If a nickname is provided, we generate an icon based on a SHA512 HMAC |
197
|
|
|
// of the users IP. (We assume that if the user did not enter a nickname, |
198
|
|
|
// the user wants to be anonymous and we will not generate an icon.) |
199
|
12 |
|
$icon = $this->_conf->getKey('icon'); |
200
|
12 |
|
if ($icon != 'none') { |
201
|
11 |
|
$pngdata = ''; |
202
|
11 |
|
$hmac = TrafficLimiter::getHash(); |
203
|
11 |
|
if ($icon == 'identicon') { |
204
|
10 |
|
$identicon = new Identicon(); |
205
|
10 |
|
$pngdata = $identicon->getImageDataUri($hmac, 16); |
206
|
1 |
|
} elseif ($icon == 'vizhash') { |
207
|
1 |
|
$vh = new Vizhash16x16(); |
208
|
1 |
|
$pngdata = 'data:image/png;base64,' . base64_encode( |
209
|
1 |
|
$vh->generate($hmac) |
210
|
|
|
); |
211
|
|
|
} |
212
|
11 |
|
if ($pngdata != '') { |
213
|
11 |
|
$this->_data->meta->vizhash = $pngdata; |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
// Once the icon is generated, we do not keep the IP address hash. |
217
|
12 |
|
} |
218
|
|
|
} |
219
|
|
|
|
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.