1 /*
2 Drawpile - a collaborative drawing program.
3
4 Copyright (C) 2015-2018 Calle Laakkonen
5
6 Drawpile is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Drawpile is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Drawpile. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "aclfilter.h"
21
22 #include "../libshared/net/meta.h"
23 #include "../libshared/net/meta2.h"
24 #include "../libshared/net/brushes.h"
25 #include "../libshared/net/image.h"
26 #include "../libshared/net/layer.h"
27 #include "../libshared/net/annotation.h"
28 #include "../libshared/net/undo.h"
29
30 namespace canvas {
31
AclFilter(QObject * parent)32 AclFilter::AclFilter(QObject *parent)
33 : QObject(parent)
34 {
35 }
36
clone(QObject * newParent) const37 AclFilter *AclFilter::clone(QObject *newParent) const
38 {
39 AclFilter *f = new AclFilter(newParent);
40
41 f->m_myId = m_myId;
42 f->m_isOperator = m_isOperator;
43 f->m_isTrusted = m_isTrusted;
44 f->m_sessionLocked = m_sessionLocked;
45 f->m_localUserLocked = m_localUserLocked;
46
47 f->m_layers = m_layers;
48 f->m_ops = m_ops;
49 f->m_trusted = m_trusted;
50 f->m_auth = m_auth;
51 f->m_userlocks = m_userlocks;
52 f->m_protectedAnnotations = m_protectedAnnotations;
53 for(int i=0;i<FeatureCount;++i)
54 f->m_featureTiers[i] = m_featureTiers[i];
55
56 return f;
57 }
58
reset(uint8_t myId,bool localMode)59 void AclFilter::reset(uint8_t myId, bool localMode)
60 {
61 m_layers.clear();
62 m_myId = myId;
63 m_isTrusted = false;
64 m_sessionLocked = false;
65 m_localUserLocked = false;
66
67 m_ops.reset();
68 m_trusted.reset();
69 m_auth.reset();
70 m_userlocks.reset();
71 m_protectedAnnotations.clear();
72
73 if(localMode)
74 m_ops.set(myId);
75 setOperator(localMode);
76
77 emit localLockChanged(false);
78
79 // Default feature access levels
80 setFeature( Feature::PutImage, Tier::Guest);
81 setFeature( Feature::RegionMove, Tier::Guest);
82 setFeature( Feature::Resize, Tier::Op);
83 setFeature( Feature::Background, Tier::Op);
84 setFeature( Feature::EditLayers, Tier::Op);
85 setFeature( Feature::OwnLayers, Tier::Guest);
86 setFeature(Feature::CreateAnnotation, Tier::Guest);
87 setFeature( Feature::Laser, Tier::Guest);
88 setFeature( Feature::Undo, Tier::Guest);
89 static_assert(FeatureCount == 9, "missing default feature tiers");
90 }
91
setOnlineMode(uint8_t myId)92 void AclFilter::setOnlineMode(uint8_t myId)
93 {
94 m_myId = myId;
95 // We will soon get the correct values for these
96 m_isOperator = false;
97 m_isTrusted = false;
98 }
99
100 // Get the ID of the layer's creator. This assumes the ID prefixing convention is used.
layerCreator(uint16_t layerId)101 static uint8_t layerCreator(uint16_t layerId) {
102 return layerId >> 8;
103 }
104
filterMessage(const protocol::Message & msg)105 bool AclFilter::filterMessage(const protocol::Message &msg)
106 {
107 using namespace protocol;
108
109 // Session and user specific locks apply to all Command type messages
110 if(msg.isCommand() && (m_sessionLocked || m_userlocks.contains(msg.contextId())))
111 return false;
112
113 // This user's access level tier determines which features are available
114 const Tier tier = userTier(msg.contextId());
115
116 switch(msg.type()) {
117 case MSG_USER_JOIN:
118 if((static_cast<const UserJoin&>(msg).flags() & UserJoin::FLAG_AUTH))
119 m_auth.set(msg.contextId());
120
121 // Make sure the user's access bits are up to date
122 emit operatorListChanged(m_ops.toList());
123 emit trustedUserListChanged(m_trusted.toList());
124
125 if(msg.contextId() == m_myId) {
126 for(int i=0;i<FeatureCount;++i)
127 emit featureAccessChanged(Feature(i), canUseFeature(Feature(i)));
128 }
129
130 break;
131
132 case MSG_USER_LEAVE: {
133 // User left: remove locks
134 m_ops.unset(msg.contextId());
135 m_trusted.unset(msg.contextId());
136 m_auth.unset(msg.contextId());
137 m_userlocks.unset(msg.contextId());
138
139 QMutableHashIterator<int,LayerAcl> i(m_layers);
140 while(i.hasNext()) {
141 i.next();
142 if(i.value().exclusive.removeAll(msg.contextId())>0)
143 emit layerAclChanged(i.key());
144 }
145
146 // Refresh UI
147 if(msg.contextId() == m_myId) {
148 setOperator(false);
149 setTrusted(false);
150 m_localUserLocked = false;
151 emit localLockChanged(isLocked());
152 }
153 break; }
154
155 case MSG_SESSION_OWNER:
156 // This command is validated by the server
157 updateSessionOwnership(static_cast<const SessionOwner&>(msg));
158 return true;
159
160 case MSG_TRUSTED_USERS:
161 // this command is validated by the server
162 updateTrustedUserList(static_cast<const TrustedUsers&>(msg));
163 return true;
164
165 case MSG_LAYER_ACL:
166 if( tier <= featureTier(Feature::EditLayers) ||
167 (tier <= featureTier(Feature::OwnLayers) && layerCreator(msg.layer()) == msg.contextId())
168 ) {
169 const auto &lmsg = static_cast<const LayerACL&>(msg);
170
171 if(lmsg.layer() == 0) {
172 // Layer 0 sets the general session lock.
173 // Exclusive user list is not used in this case.
174 if(tier > Tier::Op)
175 return false;
176 setSessionLock(lmsg.locked());
177 return true;
178 }
179
180 const Tier tier = Tier(qBound(0, int(lmsg.tier()), TierCount));
181 m_layers[lmsg.layer()] = LayerAcl { lmsg.locked(), tier, lmsg.exclusive() };
182
183 // Emit this to refresh the UI in case our selected layer was (un)locked.
184 // (We don't actually know which layer is selected in the UI here.)
185 emit localLockChanged(isLocked());
186 emit layerAclChanged(lmsg.layer());
187
188 return true;
189 }
190 return false;
191
192 case MSG_FEATURE_LEVELS: {
193 if(tier > Tier::Op)
194 return false;
195
196 const auto &flmsg = static_cast<const FeatureAccessLevels&>(msg);
197 for(int i=0;i<canvas::FeatureCount;++i) {
198 setFeature(Feature(i), Tier(qBound(0, int(flmsg.featureTier(i)), canvas::TierCount)));
199 }
200 return true;
201 }
202
203 case MSG_USER_ACL: {
204 if(tier > Tier::Op)
205 return false;
206
207 const auto &lmsg = static_cast<const UserACL&>(msg);
208 m_userlocks.setFromList(lmsg.ids());
209 emit userLocksChanged(lmsg.ids());
210 setUserLock(m_userlocks.contains(m_myId));
211 return true;
212 }
213
214 case MSG_LAYER_DEFAULT:
215 return tier == Tier::Op;
216
217 case MSG_CHAT:
218 // Only operators can pin messages
219 if(static_cast<const protocol::Chat&>(msg).isPin() && tier > Tier::Op)
220 return false;
221 break;
222
223 case MSG_LASERTRAIL:
224 return tier <= featureTier(Feature::Laser);
225
226 case MSG_CANVAS_RESIZE: return tier <= featureTier(Feature::Resize);
227 case MSG_PUTTILE: return tier == Tier::Op;
228 case MSG_CANVAS_BACKGROUND: return tier <= featureTier(Feature::Background);
229
230 case MSG_LAYER_CREATE: {
231 if(tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId()) {
232 qWarning("non-op user %d tried to create layer with context id %d", msg.contextId(), layerCreator(msg.layer()));
233 return false;
234 }
235
236 // Must have either general or ownlayer permission to create layers
237 return tier <= featureTier(Feature::EditLayers) || tier <= featureTier(Feature::OwnLayers);
238 }
239 case MSG_LAYER_ATTR:
240 if(static_cast<const protocol::LayerAttributes&>(msg).sublayer()>0 && tier > Tier::Op) {
241 // Direct sublayer editing is used only by operators during session init
242 return false;
243 }
244 Q_FALLTHROUGH();
245
246 case MSG_LAYER_RETITLE:
247 case MSG_LAYER_DELETE: {
248 const uint8_t createdBy = layerCreator(msg.layer());
249 // EDITLAYERS feature gives permission to edit all layers
250 // OWNLAYERS feature gives permission to edit layers created by this user
251 if(
252 (createdBy != msg.contextId() && tier > featureTier(Feature::EditLayers)) ||
253 (createdBy == msg.contextId() && tier > featureTier(Feature::OwnLayers))
254 )
255 return false;
256
257 if(msg.type() == MSG_LAYER_DELETE)
258 m_layers.remove(msg.layer());
259 break;
260 }
261 case MSG_LAYER_ORDER:
262 return tier <= featureTier(Feature::EditLayers);
263
264 case MSG_PUTIMAGE:
265 case MSG_FILLRECT:
266 return tier <= featureTier(Feature::PutImage) && !isLayerLockedFor(msg.layer(), msg.contextId(), tier);
267
268 case MSG_DRAWDABS_CLASSIC:
269 case MSG_DRAWDABS_PIXEL:
270 return !isLayerLockedFor(msg.layer(), msg.contextId(), tier);
271
272 case MSG_REGION_MOVE:
273 return tier <= featureTier(Feature::RegionMove) && !isLayerLockedFor(msg.layer(), msg.contextId(), tier);
274
275 case MSG_ANNOTATION_CREATE:
276 if(tier > featureTier(Feature::CreateAnnotation))
277 return false;
278
279 if(tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId()) {
280 qWarning("non-op user %d tried to create annotation with context id %d", msg.contextId(), layerCreator(msg.layer()));
281 return false;
282 }
283 break;
284 case MSG_ANNOTATION_EDIT:
285 // Non-operators can't edit protected annotations created by other users
286 if(m_protectedAnnotations.contains(layerCreator(msg.layer())) && tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId())
287 return false;
288
289 if((static_cast<const AnnotationEdit&>(msg).flags() & protocol::AnnotationEdit::FLAG_PROTECT))
290 m_protectedAnnotations.insert(msg.layer());
291 else
292 m_protectedAnnotations.remove(msg.layer());
293 break;
294 case MSG_ANNOTATION_DELETE:
295 case MSG_ANNOTATION_RESHAPE:
296 if(m_protectedAnnotations.contains(msg.layer()) && tier > Tier::Op && layerCreator(msg.layer())!=msg.contextId())
297 return false;
298 if(msg.type() == MSG_ANNOTATION_DELETE)
299 m_protectedAnnotations.remove(msg.layer());
300 break;
301
302 case MSG_UNDO:
303 if(tier > featureTier(Feature::Undo))
304 return false;
305
306 // Only operators can override Undos.
307 if(tier > Tier::Op && static_cast<const Undo&>(msg).overrideId()>0)
308 return false;
309 break;
310
311 default: break;
312 }
313
314 return true;
315 }
316
layerAcl(int layerId) const317 AclFilter::LayerAcl AclFilter::layerAcl(int layerId) const
318 {
319 if(!m_layers.contains(layerId))
320 return LayerAcl { false, Tier::Guest, QList<uint8_t>() };
321
322 return m_layers[layerId];
323 }
324
isLayerLockedFor(int layerId,uint8_t userId,Tier userTier) const325 bool AclFilter::isLayerLockedFor(int layerId, uint8_t userId, Tier userTier) const
326 {
327 if(!m_layers.contains(layerId))
328 return false;
329
330 const LayerAcl &l = m_layers[layerId];
331 // Locking a layer locks it for everyone
332 if(l.locked)
333 return true;
334
335 // If the layer has not been configured for exclusive user access,
336 // permit access by user tier
337 if(l.exclusive.isEmpty())
338 return l.tier < userTier;
339 else
340 return !l.exclusive.contains(userId);
341 }
342
updateSessionOwnership(const protocol::SessionOwner & msg)343 void AclFilter::updateSessionOwnership(const protocol::SessionOwner &msg)
344 {
345 m_ops.setFromList(msg.ids());
346 emit operatorListChanged(msg.ids());
347 setOperator(m_ops.contains(m_myId));
348 }
349
updateTrustedUserList(const protocol::TrustedUsers & msg)350 void AclFilter::updateTrustedUserList(const protocol::TrustedUsers &msg)
351 {
352 m_trusted.setFromList(msg.ids());
353 emit trustedUserListChanged(msg.ids());
354 setTrusted(m_trusted.contains(m_myId));
355 }
356
setOperator(bool op)357 void AclFilter::setOperator(bool op)
358 {
359 if(op != m_isOperator) {
360 m_isOperator = op;
361 emit localOpChanged(op);
362
363 // Op and Trusted status change affects available features
364 for(int i=0;i<FeatureCount;++i)
365 emit featureAccessChanged(Feature(i), canUseFeature(Feature(i)));
366 }
367 }
368
setTrusted(bool trusted)369 void AclFilter::setTrusted(bool trusted)
370 {
371 if(trusted != m_isTrusted) {
372 m_isTrusted = trusted;
373
374 // Op and Trusted status change affects available features
375 for(int i=0;i<FeatureCount;++i)
376 emit featureAccessChanged(Feature(i), canUseFeature(Feature(i)));
377 }
378 }
379
setSessionLock(bool lock)380 void AclFilter::setSessionLock(bool lock)
381 {
382 bool wasLocked = isLocked();
383 m_sessionLocked = lock;
384 if(wasLocked != isLocked())
385 emit localLockChanged(isLocked());
386 }
387
setUserLock(bool lock)388 void AclFilter::setUserLock(bool lock)
389 {
390 bool wasLocked = isLocked();
391 m_localUserLocked = lock;
392 if(wasLocked != isLocked())
393 emit localLockChanged(isLocked());
394 }
395
setFeature(Feature feature,Tier tier)396 void AclFilter::setFeature(Feature feature, Tier tier)
397 {
398 if(m_featureTiers[int(feature)] == tier)
399 return;
400
401 const bool hadAccess = canUseFeature(feature);
402 m_featureTiers[int(feature)] = tier;
403
404 if(canUseFeature(feature) != hadAccess)
405 emit featureAccessChanged(feature, !hadAccess);
406
407 emit featureTierChanged(feature, tier);
408 }
409
410 }
411
412