Esempio n. 1
0
void Writer::recordMessage(const protocol::Message &msg)
{
	Q_ASSERT(_file->isOpen());

	if(!_filterMeta || msg.isCommand() || isRecordableMeta(msg.type())) {
		// Write Interval message if sufficient time has passed since last message was written
		if(_minInterval>0) {
			qint64 now = QDateTime::currentMSecsSinceEpoch();
			qint64 interval = now - _interval;
			if(interval >= _minInterval) {
				protocol::Interval imsg(qMin(qint64(0xffff), interval));
				QVarLengthArray<char> ibuf(imsg.length());
				int ilen = imsg.serialize(ibuf.data());
				_file->write(ibuf.data(), ilen);
			}
			_interval = now;
		}

		// Write the actual message
		QVarLengthArray<char> buf(msg.length());
		int len = msg.serialize(buf.data());
		Q_ASSERT(len == buf.length());
		_file->write(buf.data(), len);
	}
}
Esempio n. 2
0
bool AclFilter::filterMessage(const protocol::Message &msg)
{
	using namespace protocol;

	// Session and user specific locks apply to all Command type messages
	if(msg.isCommand() && (m_sessionLocked || m_userlocks.contains(msg.contextId())))
		return false;

	// This user's access level tier determines which features are available
	const Tier tier = userTier(msg.contextId());

	switch(msg.type()) {
	case MSG_USER_JOIN:
		if((static_cast<const UserJoin&>(msg).flags() & UserJoin::FLAG_AUTH))
			m_auth.set(msg.contextId());

		// Make sure the user's access bits are up to date
		emit operatorListChanged(m_ops.toList());
		emit trustedUserListChanged(m_trusted.toList());

		if(msg.contextId() == m_myId) {
			for(int i=0;i<FeatureCount;++i)
				emit featureAccessChanged(Feature(i), canUseFeature(Feature(i)));
		}

		break;

	case MSG_USER_LEAVE: {
		// User left: remove locks
		m_ops.unset(msg.contextId());
		m_trusted.unset(msg.contextId());
		m_auth.unset(msg.contextId());
		m_userlocks.unset(msg.contextId());

		QMutableHashIterator<int,LayerAcl> i(m_layers);
		while(i.hasNext()) {
			i.next();
			if(i.value().exclusive.removeAll(msg.contextId())>0)
				emit layerAclChanged(i.key());
		}

		// Refresh UI
		if(msg.contextId() == m_myId) {
			setOperator(false);
			setTrusted(false);
			m_localUserLocked = false;
			emit localLockChanged(isLocked());
		}
		break; }

	case MSG_SESSION_OWNER:
		// This command is validated by the server
		updateSessionOwnership(static_cast<const SessionOwner&>(msg));
		return true;

	case MSG_TRUSTED_USERS:
		// this command is validated by the server
		updateTrustedUserList(static_cast<const TrustedUsers&>(msg));
		return true;

	case MSG_LAYER_ACL:
		if( tier <= featureTier(Feature::EditLayers) ||
		   (tier <= featureTier(Feature::OwnLayers) && layerCreator(msg.layer()) == msg.contextId())
		) {
			const auto &lmsg = static_cast<const LayerACL&>(msg);

			if(lmsg.layer() == 0) {
				// Layer 0 sets the general session lock.
				// Exclusive user list is not used in this case.
				if(tier > Tier::Op)
					return false;
				setSessionLock(lmsg.locked());
				return true;
			}

			const Tier tier = Tier(qBound(0, int(lmsg.tier()), TierCount));
			m_layers[lmsg.layer()] = LayerAcl { lmsg.locked(), tier, lmsg.exclusive() };

			// Emit this to refresh the UI in case our selected layer was (un)locked.
			// (We don't actually know which layer is selected in the UI here.)
			emit localLockChanged(isLocked());
			emit layerAclChanged(lmsg.layer());

			return true;
		}
		return false;

	case MSG_FEATURE_LEVELS: {
		if(tier > Tier::Op)
			return false;

		const auto &flmsg = static_cast<const FeatureAccessLevels&>(msg);
		for(int i=0;i<canvas::FeatureCount;++i) {
			setFeature(Feature(i), Tier(qBound(0, int(flmsg.featureTier(i)), canvas::TierCount)));
		}
		return true;
	}

	case MSG_USER_ACL: {
		if(tier > Tier::Op)
			return false;

		const auto &lmsg = static_cast<const UserACL&>(msg);
		m_userlocks.setFromList(lmsg.ids());
		emit userLocksChanged(lmsg.ids());
		setUserLock(m_userlocks.contains(m_myId));
		return true;
	}

	case MSG_LAYER_DEFAULT:
		return tier == Tier::Op;

	case MSG_CHAT:
		// Only operators can pin messages
		if(static_cast<const protocol::Chat&>(msg).isPin() && tier > Tier::Op)
			return false;
		break;

	case MSG_LASERTRAIL:
		return tier <= featureTier(Feature::Laser);

	case MSG_CANVAS_RESIZE: return tier <= featureTier(Feature::Resize);
	case MSG_PUTTILE: return tier == Tier::Op;
	case MSG_CANVAS_BACKGROUND: return tier <= featureTier(Feature::Background);

	case MSG_LAYER_CREATE: {
		if(tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId()) {
			qWarning("non-op user %d tried to create layer with context id %d", msg.contextId(), layerCreator(msg.layer()));
			return false;
		}

		// Must have either general or ownlayer permission to create layers
		return tier <= featureTier(Feature::EditLayers) || tier <= featureTier(Feature::OwnLayers);
	}
	case MSG_LAYER_ATTR:
		if(static_cast<const protocol::LayerAttributes&>(msg).sublayer()>0 && tier > Tier::Op) {
			// Direct sublayer editing is used only by operators during session init
			return false;
		}
		Q_FALLTHROUGH();

	case MSG_LAYER_RETITLE:
	case MSG_LAYER_DELETE: {
		const uint8_t createdBy = layerCreator(msg.layer());
		// EDITLAYERS feature gives permission to edit all layers
		// OWNLAYERS feature gives permission to edit layers created by this user
		if(
			(createdBy != msg.contextId() && tier > featureTier(Feature::EditLayers)) ||
			(createdBy == msg.contextId() && tier > featureTier(Feature::OwnLayers))
		  )
			return false;

		if(msg.type() == MSG_LAYER_DELETE)
			m_layers.remove(msg.layer());
		break;
	}
	case MSG_LAYER_ORDER:
		return tier <= featureTier(Feature::EditLayers);

	case MSG_PUTIMAGE:
	case MSG_FILLRECT:
		return tier <= featureTier(Feature::PutImage) && !isLayerLockedFor(msg.layer(), msg.contextId(), tier);

	case MSG_DRAWDABS_CLASSIC:
	case MSG_DRAWDABS_PIXEL:
		return !isLayerLockedFor(msg.layer(), msg.contextId(), tier);

	case MSG_REGION_MOVE:
		return tier <= featureTier(Feature::RegionMove) && !isLayerLockedFor(msg.layer(), msg.contextId(), tier);

	case MSG_ANNOTATION_CREATE:
		if(tier > featureTier(Feature::CreateAnnotation))
			return false;

		if(tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId()) {
			qWarning("non-op user %d tried to create annotation with context id %d", msg.contextId(), layerCreator(msg.layer()));
			return false;
		}
		break;
	case MSG_ANNOTATION_EDIT:
		// Non-operators can't edit protected annotations created by other users
		if(m_protectedAnnotations.contains(layerCreator(msg.layer())) && tier > Tier::Op && layerCreator(msg.layer()) != msg.contextId())
			return false;

		if((static_cast<const AnnotationEdit&>(msg).flags() & protocol::AnnotationEdit::FLAG_PROTECT))
			m_protectedAnnotations.insert(msg.layer());
		else
			m_protectedAnnotations.remove(msg.layer());
		break;
	case MSG_ANNOTATION_DELETE:
	case MSG_ANNOTATION_RESHAPE:
		if(m_protectedAnnotations.contains(msg.layer()) && tier > Tier::Op && layerCreator(msg.layer())!=msg.contextId())
			return false;
		if(msg.type() == MSG_ANNOTATION_DELETE)
			m_protectedAnnotations.remove(msg.layer());
		break;

	case MSG_UNDO:
		if(tier > featureTier(Feature::Undo))
			return false;

		// Only operators can override Undos.
		if(tier > Tier::Op && static_cast<const Undo&>(msg).overrideId()>0)
			return false;
		break;

	default: break;
	}

	return true;
}