QVector<Character*>* GroupExpression::eval(Card* caster, const Event* e) const { QVector<Character*>* group = caster->owner()->game()->charactersByPlayTime(caster->owner(), m_owner, m_type); if (!m_excludedTargets.isNull()) { QVector<Character*>* excluded = m_excludedTargets.data()->eval(caster, NULL, e); foreach (Character* c, *excluded) group->removeOne(c); delete excluded; } return group; }
bool OMEMO::encryptMessage(const QString &ownJid, int account, QDomElement &xml, bool buildSessions, const uint32_t *toDeviceId) { std::shared_ptr<Signal> signal = getSignal(account); QString recipient = m_contactInfoAccessor->realJid(account, xml.attribute("to")).split("/").first(); bool isGroup = xml.attribute("type") == "groupchat"; if (!isEnabledForUser(account, recipient)) { return false; } if (buildSessions) { QMap<QString, QVector<uint32_t>> invalidSessions; QVector<uint32_t> invalidSessionsWithOwnDevices; if (isGroup) { forEachMucParticipant(account, ownJid, recipient, [&](const QString &userJid) { QVector<uint32_t> sessions = signal->invalidSessions(userJid); if (!sessions.isEmpty()) { invalidSessions.insert(userJid, sessions); } return true; }); } else { QVector<uint32_t> sessions = signal->invalidSessions(recipient); if (!sessions.isEmpty()) { invalidSessions.insert(recipient, sessions); } } invalidSessionsWithOwnDevices = signal->invalidSessions(ownJid); invalidSessionsWithOwnDevices.removeOne(signal->getDeviceId()); if (!invalidSessions.isEmpty() || !invalidSessionsWithOwnDevices.isEmpty()) { buildSessionsFromBundle(invalidSessions, invalidSessionsWithOwnDevices, ownJid, account, xml); xml = QDomElement(); return true; } } signal->processUndecidedDevices(recipient, false); signal->processUndecidedDevices(ownJid, true); QDomElement encrypted = xml.ownerDocument().createElementNS(OMEMO_XMLNS, "encrypted"); QDomElement header = xml.ownerDocument().createElement("header"); header.setAttribute("sid", signal->getDeviceId()); encrypted.appendChild(header); xml.appendChild(encrypted); QByteArray iv = Crypto::randomBytes(OMEMO_AES_GCM_IV_LENGTH); QDomElement ivElement = xml.ownerDocument().createElement("iv"); ivElement.appendChild(xml.ownerDocument().createTextNode(iv.toBase64())); header.appendChild(ivElement); QByteArray key = Crypto::randomBytes(OMEMO_AES_128_KEY_LENGTH); QDomElement body = xml.firstChildElement("body"); QPair<QByteArray, QByteArray> encryptedBody; if (!body.isNull()) { QString plainText = body.firstChild().nodeValue(); encryptedBody = Crypto::aes_gcm(Crypto::Encode, iv, key, plainText.toUtf8()); key += encryptedBody.second; } QList<EncryptedKey> encryptedKeys; if (isGroup) { forEachMucParticipant(account, ownJid, recipient, [&](const QString &userJid) { encryptedKeys.append(signal->encryptKey(ownJid, userJid, key)); return true; }); } else { encryptedKeys = signal->encryptKey(ownJid, recipient, key); } if (encryptedKeys.isEmpty()) { m_accountController->appendSysMsg(account, xml.attribute("to"), "[OMEMO] Unable to build any sessions, the message was not sent"); xml = QDomElement(); } else { foreach (EncryptedKey encKey, encryptedKeys) { if (toDeviceId != nullptr && *toDeviceId != encKey.deviceId) { continue; } QDomElement keyElement = xml.ownerDocument().createElement("key"); keyElement.setAttribute("rid", encKey.deviceId); if (encKey.isPreKey) { keyElement.setAttribute("prekey", 1); } setNodeText(keyElement, encKey.key); header.appendChild(keyElement); } if (!body.isNull()) { if (isGroup) { m_encryptedGroupMessages.insert(xml.attribute("id"), body.firstChild().nodeValue()); } xml.removeChild(body); QDomElement payload = xml.ownerDocument().createElement("payload"); payload.appendChild(xml.ownerDocument().createTextNode(encryptedBody.first.toBase64())); encrypted.appendChild(payload); QDomElement html = xml.firstChildElement("html"); if (!html.isNull()) { xml.removeChild(html); } } xml.appendChild(xml.ownerDocument().createElementNS("urn:xmpp:hints", "store")); QDomElement encryption = xml.ownerDocument().createElementNS("urn:xmpp:eme:0", "encryption"); encryption.setAttribute("namespace", OMEMO_XMLNS); encryption.setAttribute("name", "OMEMO"); xml.appendChild(encryption); } return true; }