api_user_privacy.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "api/api_user_privacy.h"
  8. #include "apiwrap.h"
  9. #include "data/data_chat.h"
  10. #include "data/data_channel.h"
  11. #include "data/data_peer.h"
  12. #include "data/data_peer_id.h"
  13. #include "data/data_session.h"
  14. #include "data/data_user.h"
  15. #include "main/main_session.h"
  16. #include "settings/settings_premium.h" // Settings::ShowPremium.
  17. namespace Api {
  18. namespace {
  19. constexpr auto kMaxRules = 3; // Allow users, disallow users, Option.
  20. using TLInputRules = MTPVector<MTPInputPrivacyRule>;
  21. using TLRules = MTPVector<MTPPrivacyRule>;
  22. TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
  23. using Exceptions = UserPrivacy::Exceptions;
  24. const auto collectInputUsers = [](const Exceptions &exceptions) {
  25. const auto &peers = exceptions.peers;
  26. auto result = QVector<MTPInputUser>();
  27. result.reserve(peers.size());
  28. for (const auto &peer : peers) {
  29. if (const auto user = peer->asUser()) {
  30. result.push_back(user->inputUser);
  31. }
  32. }
  33. return result;
  34. };
  35. const auto collectInputChats = [](const Exceptions &exceptions) {
  36. const auto &peers = exceptions.peers;
  37. auto result = QVector<MTPlong>();
  38. result.reserve(peers.size());
  39. for (const auto &peer : peers) {
  40. if (!peer->isUser()) {
  41. result.push_back(peerToBareMTPInt(peer->id));
  42. }
  43. }
  44. return result;
  45. };
  46. using Option = UserPrivacy::Option;
  47. auto result = QVector<MTPInputPrivacyRule>();
  48. result.reserve(kMaxRules);
  49. if (!rule.ignoreAlways) {
  50. const auto users = collectInputUsers(rule.always);
  51. const auto chats = collectInputChats(rule.always);
  52. if (!users.empty()) {
  53. result.push_back(
  54. MTP_inputPrivacyValueAllowUsers(
  55. MTP_vector<MTPInputUser>(users)));
  56. }
  57. if (!chats.empty()) {
  58. result.push_back(
  59. MTP_inputPrivacyValueAllowChatParticipants(
  60. MTP_vector<MTPlong>(chats)));
  61. }
  62. if (rule.always.premiums && (rule.option != Option::Everyone)) {
  63. result.push_back(MTP_inputPrivacyValueAllowPremium());
  64. }
  65. if (rule.always.miniapps && (rule.option != Option::Everyone)) {
  66. result.push_back(MTP_inputPrivacyValueAllowBots());
  67. }
  68. }
  69. if (!rule.ignoreNever) {
  70. const auto users = collectInputUsers(rule.never);
  71. const auto chats = collectInputChats(rule.never);
  72. if (!users.empty()) {
  73. result.push_back(
  74. MTP_inputPrivacyValueDisallowUsers(
  75. MTP_vector<MTPInputUser>(users)));
  76. }
  77. if (!chats.empty()) {
  78. result.push_back(
  79. MTP_inputPrivacyValueDisallowChatParticipants(
  80. MTP_vector<MTPlong>(chats)));
  81. }
  82. if (rule.never.miniapps && (rule.option != Option::Nobody)) {
  83. result.push_back(MTP_inputPrivacyValueDisallowBots());
  84. }
  85. }
  86. result.push_back([&] {
  87. switch (rule.option) {
  88. case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
  89. case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
  90. case Option::CloseFriends:
  91. return MTP_inputPrivacyValueAllowCloseFriends();
  92. case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
  93. }
  94. Unexpected("Option value in Api::UserPrivacy::RulesToTL.");
  95. }());
  96. return MTP_vector<MTPInputPrivacyRule>(std::move(result));
  97. }
  98. UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) {
  99. // This is simplified version of privacy rules interpretation.
  100. // But it should be fine for all the apps
  101. // that use the same subset of features.
  102. using Option = UserPrivacy::Option;
  103. auto result = UserPrivacy::Rule();
  104. auto optionSet = false;
  105. const auto setOption = [&](Option option) {
  106. if (optionSet) {
  107. return;
  108. }
  109. optionSet = true;
  110. result.option = option;
  111. };
  112. auto &always = result.always.peers;
  113. auto &never = result.never.peers;
  114. const auto feed = [&](const MTPPrivacyRule &rule) {
  115. rule.match([&](const MTPDprivacyValueAllowAll &) {
  116. setOption(Option::Everyone);
  117. }, [&](const MTPDprivacyValueAllowContacts &) {
  118. setOption(Option::Contacts);
  119. }, [&](const MTPDprivacyValueAllowCloseFriends &) {
  120. setOption(Option::CloseFriends);
  121. }, [&](const MTPDprivacyValueAllowPremium &) {
  122. result.always.premiums = true;
  123. }, [&](const MTPDprivacyValueAllowBots &) {
  124. result.always.miniapps = true;
  125. }, [&](const MTPDprivacyValueDisallowBots &) {
  126. result.never.miniapps = true;
  127. }, [&](const MTPDprivacyValueAllowUsers &data) {
  128. const auto &users = data.vusers().v;
  129. always.reserve(always.size() + users.size());
  130. for (const auto &userId : users) {
  131. const auto user = owner.user(UserId(userId.v));
  132. if (!base::contains(never, user)
  133. && !base::contains(always, user)) {
  134. always.emplace_back(user);
  135. }
  136. }
  137. }, [&](const MTPDprivacyValueAllowChatParticipants &data) {
  138. const auto &chats = data.vchats().v;
  139. always.reserve(always.size() + chats.size());
  140. for (const auto &chatId : chats) {
  141. const auto chat = owner.chatLoaded(chatId);
  142. const auto peer = chat
  143. ? static_cast<PeerData*>(chat)
  144. : owner.channelLoaded(chatId);
  145. if (peer
  146. && !base::contains(never, peer)
  147. && !base::contains(always, peer)) {
  148. always.emplace_back(peer);
  149. }
  150. }
  151. }, [&](const MTPDprivacyValueDisallowContacts &) {
  152. // Not supported
  153. }, [&](const MTPDprivacyValueDisallowAll &) {
  154. setOption(Option::Nobody);
  155. }, [&](const MTPDprivacyValueDisallowUsers &data) {
  156. const auto &users = data.vusers().v;
  157. never.reserve(never.size() + users.size());
  158. for (const auto &userId : users) {
  159. const auto user = owner.user(UserId(userId.v));
  160. if (!base::contains(always, user)
  161. && !base::contains(never, user)) {
  162. never.emplace_back(user);
  163. }
  164. }
  165. }, [&](const MTPDprivacyValueDisallowChatParticipants &data) {
  166. const auto &chats = data.vchats().v;
  167. never.reserve(never.size() + chats.size());
  168. for (const auto &chatId : chats) {
  169. const auto chat = owner.chatLoaded(chatId);
  170. const auto peer = chat
  171. ? static_cast<PeerData*>(chat)
  172. : owner.channelLoaded(chatId);
  173. if (peer
  174. && !base::contains(always, peer)
  175. && !base::contains(never, peer)) {
  176. never.emplace_back(peer);
  177. }
  178. }
  179. });
  180. };
  181. for (const auto &rule : rules.v) {
  182. feed(rule);
  183. }
  184. feed(MTP_privacyValueDisallowAll()); // Disallow by default.
  185. return result;
  186. }
  187. MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
  188. using Key = UserPrivacy::Key;
  189. switch (key) {
  190. case Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
  191. case Key::Invites: return MTP_inputPrivacyKeyChatInvite();
  192. case Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
  193. case Key::AddedByPhone: return MTP_inputPrivacyKeyAddedByPhone();
  194. case Key::LastSeen: return MTP_inputPrivacyKeyStatusTimestamp();
  195. case Key::CallsPeer2Peer: return MTP_inputPrivacyKeyPhoneP2P();
  196. case Key::Forwards: return MTP_inputPrivacyKeyForwards();
  197. case Key::ProfilePhoto: return MTP_inputPrivacyKeyProfilePhoto();
  198. case Key::Voices: return MTP_inputPrivacyKeyVoiceMessages();
  199. case Key::About: return MTP_inputPrivacyKeyAbout();
  200. case Key::Birthday: return MTP_inputPrivacyKeyBirthday();
  201. case Key::GiftsAutoSave: return MTP_inputPrivacyKeyStarGiftsAutoSave();
  202. case Key::NoPaidMessages: return MTP_inputPrivacyKeyNoPaidMessages();
  203. }
  204. Unexpected("Key in Api::UserPrivacy::KetToTL.");
  205. }
  206. std::optional<UserPrivacy::Key> TLToKey(mtpTypeId type) {
  207. using Key = UserPrivacy::Key;
  208. switch (type) {
  209. case mtpc_privacyKeyPhoneNumber:
  210. case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber;
  211. case mtpc_privacyKeyAddedByPhone:
  212. case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone;
  213. case mtpc_privacyKeyStatusTimestamp:
  214. case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen;
  215. case mtpc_privacyKeyChatInvite:
  216. case mtpc_inputPrivacyKeyChatInvite: return Key::Invites;
  217. case mtpc_privacyKeyPhoneCall:
  218. case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls;
  219. case mtpc_privacyKeyPhoneP2P:
  220. case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer;
  221. case mtpc_privacyKeyForwards:
  222. case mtpc_inputPrivacyKeyForwards: return Key::Forwards;
  223. case mtpc_privacyKeyProfilePhoto:
  224. case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
  225. case mtpc_privacyKeyVoiceMessages:
  226. case mtpc_inputPrivacyKeyVoiceMessages: return Key::Voices;
  227. case mtpc_privacyKeyAbout:
  228. case mtpc_inputPrivacyKeyAbout: return Key::About;
  229. case mtpc_privacyKeyBirthday:
  230. case mtpc_inputPrivacyKeyBirthday: return Key::Birthday;
  231. case mtpc_privacyKeyStarGiftsAutoSave:
  232. case mtpc_inputPrivacyKeyStarGiftsAutoSave: return Key::GiftsAutoSave;
  233. case mtpc_privacyKeyNoPaidMessages:
  234. case mtpc_inputPrivacyKeyNoPaidMessages: return Key::NoPaidMessages;
  235. }
  236. return std::nullopt;
  237. }
  238. } // namespace
  239. UserPrivacy::UserPrivacy(not_null<ApiWrap*> api)
  240. : _session(&api->session())
  241. , _api(&api->instance()) {
  242. }
  243. void UserPrivacy::save(
  244. Key key,
  245. const UserPrivacy::Rule &rule) {
  246. const auto tlKey = KeyToTL(key);
  247. const auto keyTypeId = tlKey.type();
  248. const auto it = _privacySaveRequests.find(keyTypeId);
  249. if (it != _privacySaveRequests.cend()) {
  250. _api.request(it->second).cancel();
  251. _privacySaveRequests.erase(it);
  252. }
  253. const auto requestId = _api.request(MTPaccount_SetPrivacy(
  254. tlKey,
  255. RulesToTL(rule)
  256. )).done([=](const MTPaccount_PrivacyRules &result) {
  257. result.match([&](const MTPDaccount_privacyRules &data) {
  258. _session->data().processUsers(data.vusers());
  259. _session->data().processChats(data.vchats());
  260. _privacySaveRequests.remove(keyTypeId);
  261. apply(keyTypeId, data.vrules(), true);
  262. });
  263. }).fail([=](const MTP::Error &error) {
  264. const auto message = error.type();
  265. if (message == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
  266. Settings::ShowPremium(_session, QString());
  267. }
  268. _privacySaveRequests.remove(keyTypeId);
  269. }).send();
  270. _privacySaveRequests.emplace(keyTypeId, requestId);
  271. }
  272. void UserPrivacy::apply(
  273. mtpTypeId type,
  274. const TLRules &rules,
  275. bool allLoaded) {
  276. if (const auto key = TLToKey(type)) {
  277. if (!allLoaded) {
  278. reload(*key);
  279. return;
  280. }
  281. pushPrivacy(*key, rules);
  282. if ((*key) == Key::LastSeen) {
  283. _session->api().updatePrivacyLastSeens();
  284. }
  285. }
  286. }
  287. void UserPrivacy::reload(Key key) {
  288. if (_privacyRequestIds.contains(key)) {
  289. return;
  290. }
  291. const auto requestId = _api.request(MTPaccount_GetPrivacy(
  292. KeyToTL(key)
  293. )).done([=](const MTPaccount_PrivacyRules &result) {
  294. _privacyRequestIds.erase(key);
  295. result.match([&](const MTPDaccount_privacyRules &data) {
  296. _session->data().processUsers(data.vusers());
  297. _session->data().processChats(data.vchats());
  298. pushPrivacy(key, data.vrules());
  299. });
  300. }).fail([=] {
  301. _privacyRequestIds.erase(key);
  302. }).send();
  303. _privacyRequestIds.emplace(key, requestId);
  304. }
  305. void UserPrivacy::pushPrivacy(Key key, const TLRules &rules) {
  306. const auto &saved
  307. = (_privacyValues[key] = TLToRules(rules, _session->data()));
  308. const auto i = _privacyChanges.find(key);
  309. if (i != end(_privacyChanges)) {
  310. i->second.fire_copy(saved);
  311. }
  312. }
  313. auto UserPrivacy::value(Key key) -> rpl::producer<UserPrivacy::Rule> {
  314. if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) {
  315. return _privacyChanges[key].events_starting_with_copy(i->second);
  316. } else {
  317. return _privacyChanges[key].events();
  318. }
  319. }
  320. } // namespace Api