From 602e242114284a9eed1185c3008c2584706b4f0a Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sat, 12 Feb 2022 02:17:35 +0400 Subject: [PATCH] Respect restriction_reason --- src/components/chat/bubbles.ts | 19 ++++-- src/components/chat/chat.ts | 6 +- src/components/peerProfile.ts | 58 ++++++------------- src/helpers/restrictions.ts | 25 ++++++++ src/layer.d.ts | 3 +- src/lib/appManagers/appChatsManager.ts | 8 +++ src/lib/appManagers/appDialogsManager.ts | 3 +- src/lib/appManagers/appMessagesManager.ts | 61 +++++++++++++++++++- src/lib/appManagers/appPeersManager.ts | 21 ++++++- src/lib/appManagers/appProfileManager.ts | 4 -- src/lib/appManagers/appUsersManager.ts | 8 +++ src/lib/mtproto/mtprotoworker.ts | 4 +- src/scripts/in/schema_additional_params.json | 5 -- 13 files changed, 160 insertions(+), 65 deletions(-) create mode 100644 src/helpers/restrictions.ts diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index d0eede85..87f3213e 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -2222,7 +2222,7 @@ export default class ChatBubbles { const chatType = this.chat.type; - if(chatType === 'scheduled') { + if(chatType === 'scheduled' || this.chat.isRestricted) { lastMsgId = 0; } @@ -2296,7 +2296,7 @@ export default class ChatBubbles { } // add last message, bc in getHistory will load < max_id - const additionMsgId = isJump || chatType === 'scheduled' ? 0 : topMessage; + const additionMsgId = isJump || chatType === 'scheduled' || this.chat.isRestricted ? 0 : topMessage; /* this.setPeerPromise = null; this.preloader.detach(); @@ -4103,7 +4103,7 @@ export default class ChatBubbles { return promise; } - private renderEmptyPlaceholder(type: 'group' | 'saved' | 'noMessages' | 'noScheduledMessages' | 'greeting', bubble: HTMLElement, message: any, elements: (Node | string)[]) { + private renderEmptyPlaceholder(type: 'group' | 'saved' | 'noMessages' | 'noScheduledMessages' | 'greeting' | 'restricted', bubble: HTMLElement, message: any, elements: (Node | string)[]) { const BASE_CLASS = 'empty-bubble-placeholder'; bubble.classList.add(BASE_CLASS, BASE_CLASS + '-' + type); @@ -4112,6 +4112,10 @@ export default class ChatBubbles { else if(type === 'saved') title = i18n('ChatYourSelfTitle'); else if(type === 'noMessages' || type === 'greeting') title = i18n('NoMessages'); else if(type === 'noScheduledMessages') title = i18n('NoScheduledMessages'); + else if(type === 'restricted') { + title = document.createElement('span'); + title.innerText = this.appPeersManager.getRestrictionReasonText(this.peerId); + } title.classList.add('center', BASE_CLASS + '-title'); elements.push(title); @@ -4219,7 +4223,9 @@ export default class ChatBubbles { const elements: (Node | string)[] = []; const isBot = this.appPeersManager.isBot(this.peerId); - if(isSponsored) { + if(this.chat.isRestricted) { + this.renderEmptyPlaceholder('restricted', bubble, message, elements); + } else if(isSponsored) { let text: LangPackKey, mid: number, startParam: string, callback: () => void; bubble.classList.add('avoid-selection'); @@ -4368,7 +4374,7 @@ export default class ChatBubbles { return; } */ - if(side === 'bottom' && this.appPeersManager.isBroadcast(this.peerId)/* && false */) { + if(side === 'bottom' && this.appPeersManager.isBroadcast(this.peerId) && !this.chat.isRestricted/* && false */) { const {mid} = this.generateLocalMessageId(SPONSORED_MESSAGE_ID_OFFSET); if(value) { const middleware = this.getMiddleware(() => { @@ -4420,7 +4426,7 @@ export default class ChatBubbles { } } - if(side === 'top' && value && this.appPeersManager.isBot(this.peerId)) { + if(side === 'top' && value && this.appPeersManager.isBot(this.peerId) && !this.chat.isRestricted) { this.log('inject bot description'); const middleware = this.getMiddleware(); @@ -4450,6 +4456,7 @@ export default class ChatBubbles { this.scrollable.loadedAll.bottom && this.emptyPlaceholderMid === undefined && ( + this.chat.isRestricted || !this.appMessagesManager.getHistoryStorage(this.peerId).count || ( Object.keys(this.bubbles).length && diff --git a/src/components/chat/chat.ts b/src/components/chat/chat.ts index 3428128b..34beddae 100644 --- a/src/components/chat/chat.ts +++ b/src/components/chat/chat.ts @@ -74,8 +74,11 @@ export default class Chat extends EventListenerBase<{ public noForwards: boolean; public inited: boolean; + + public isRestricted: boolean; - constructor(public appImManager: AppImManager, + constructor( + public appImManager: AppImManager, public appChatsManager: AppChatsManager, public appDocsManager: AppDocsManager, public appInlineBotsManager: AppInlineBotsManager, @@ -306,6 +309,7 @@ export default class Chat extends EventListenerBase<{ } this.noForwards = this.appPeersManager.noForwards(peerId); + this.isRestricted = this.appPeersManager.isRestricted(peerId); this.container.classList.toggle('no-forwards', this.noForwards); appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId); diff --git a/src/components/peerProfile.ts b/src/components/peerProfile.ts index c6dd1363..9781f160 100644 --- a/src/components/peerProfile.ts +++ b/src/components/peerProfile.ts @@ -8,7 +8,7 @@ import IS_PARALLAX_SUPPORTED from "../environment/parallaxSupport"; import { copyTextToClipboard } from "../helpers/clipboard"; import replaceContent from "../helpers/dom/replaceContent"; import { fastRaf } from "../helpers/schedulers"; -import { User } from "../layer"; +import { ChatFull, User } from "../layer"; import { Channel } from "../lib/appManagers/appChatsManager"; import appImManager from "../lib/appManagers/appImManager"; import appMessagesManager from "../lib/appManagers/appMessagesManager"; @@ -318,52 +318,28 @@ export default class PeerProfile { const peerId = this.peerId; const threadId = this.threadId; - if(!peerId) { + if(!peerId || appPeersManager.isRestricted(peerId)) { return; } - let promise: Promise; - if(peerId.isUser()) { - promise = Promise.resolve(appProfileManager.getProfile(peerId, override)).then(userFull => { - if(this.peerId !== peerId || this.threadId !== threadId) { - //this.log.warn('peer changed'); - return false; - } - - if(userFull.rAbout && peerId !== rootScope.myId) { - setText(userFull.rAbout, this.bio); - } - - //this.log('userFull', userFull); - return true; - }); - } else { - promise = Promise.resolve(appProfileManager.getChatFull(peerId.toChatId(), override)).then((chatFull) => { - if(this.peerId !== peerId || this.threadId !== threadId) { - //this.log.warn('peer changed'); - return false; - } - - //this.log('chatInfo res 2:', chatFull); - - if(chatFull.about) { - setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio); - } + Promise.resolve(appProfileManager.getProfileByPeerId(peerId, override)).then((peerFull) => { + if(this.peerId !== peerId || this.threadId !== threadId || appPeersManager.isRestricted(peerId)) { + //this.log.warn('peer changed'); + return; + } + + //this.log('chatInfo res 2:', chatFull); + + if(peerFull.about) { + setText(RichTextProcessor.wrapRichText(peerFull.about), this.bio); + } + if((peerFull as ChatFull.channelFull)?.location?._ == 'channelLocation') { // @ts-ignore - if(chatFull?.location?._ == 'channelLocation') { - // @ts-ignore - setText(chatFull.location.address, this.location); - } - - return true; - }); - } - - promise.then((canSetNext) => { - if(canSetNext) { - this.setMoreDetailsTimeout = window.setTimeout(() => this.setMoreDetails(true), 60e3); + setText(chatFull.location.address, this.location); } + + this.setMoreDetailsTimeout = window.setTimeout(() => this.setMoreDetails(true), 60e3); }); } diff --git a/src/helpers/restrictions.ts b/src/helpers/restrictions.ts new file mode 100644 index 00000000..dd0a2727 --- /dev/null +++ b/src/helpers/restrictions.ts @@ -0,0 +1,25 @@ +import { RestrictionReason } from "../layer"; + +const platforms = new Set([ + 'all', + 'web', + 'webk' +]); + +const ignore = new Set(); + +export function getRestrictionReason(reasons: RestrictionReason[]) { + // return reasons[0]; + return reasons.find(reason => platforms.has(reason.platform) && !ignore.has(reason.reason)); +} + +export function isRestricted(reasons: RestrictionReason[]) { + return !!getRestrictionReason(reasons); +} + +export function ignoreRestrictionReasons(reasons: string[]) { + ignore.clear(); + reasons.forEach(reason => { + ignore.add(reason); + }); +} diff --git a/src/layer.d.ts b/src/layer.d.ts index 59ccfafc..0ef22be9 100644 --- a/src/layer.d.ts +++ b/src/layer.d.ts @@ -1655,8 +1655,7 @@ export namespace UserFull { folder_id?: number, ttl_period?: number, theme_emoticon?: string, - private_forward_name?: string, - rAbout?: string + private_forward_name?: string }; } diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts index 10b5aa25..75c803ba 100644 --- a/src/lib/appManagers/appChatsManager.ts +++ b/src/lib/appManagers/appChatsManager.ts @@ -11,6 +11,7 @@ import { MOUNT_CLASS_TO } from "../../config/debug"; import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object"; +import { isRestricted } from "../../helpers/restrictions"; import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatParticipant, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, Update, Updates, ChannelsCreateChannel } from "../../layer"; import apiManagerProxy from "../mtproto/mtprotoworker"; import apiManager from '../mtproto/mtprotoworker'; @@ -779,6 +780,13 @@ export class AppChatsManager { apiUpdatesManager.processUpdateMessage(updates); }); } + + public isRestricted(chatId: ChatId) { + const chat: Chat.channel = this.getChat(chatId); + const restrictionReasons = chat.restriction_reason; + + return !!(chat.pFlags.restricted && restrictionReasons && isRestricted(restrictionReasons)); + } } const appChatsManager = new AppChatsManager(); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 33edcc9d..1a7b99fd 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1448,6 +1448,7 @@ export class AppDialogsManager { } const peerId = dialog.peerId; + const isRestricted = lastMessage && appMessagesManager.isRestricted(lastMessage); //let peerId = appMessagesManager.getMessagePeer(lastMessage); //console.log('setting last message:', lastMessage); @@ -1455,7 +1456,7 @@ export class AppDialogsManager { /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ { let mediaContainer: HTMLElement; - if(!lastMessage.deleted && !draftMessage) { + if(!lastMessage.deleted && !draftMessage && !isRestricted) { const media: MyDocument | MyPhoto = appMessagesManager.getMediaFromMessage(lastMessage); if(media && (media._ === 'photo' || (['video', 'gif'] as MyDocument['type'][]).includes(media.type))) { const size = appPhotosManager.choosePhotoSize(media, 20, 20); diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 45f3c49f..b6dd6327 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -17,7 +17,7 @@ import { createPosterForVideo } from "../../helpers/files"; import { copy, deepEqual, getObjectKeysAndSort } from "../../helpers/object"; import { randomLong } from "../../helpers/random"; import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string"; -import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction } from "../../layer"; +import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter } from "../../layer"; import { InvokeApiOptions } from "../../types"; import I18n, { FormatterArguments, i18n, join, langPack, LangPackKey, UNSUPPORTED_LANG_PACK_KEY, _i18n } from "../langPack"; import { logger, LogTypes } from "../logger"; @@ -64,6 +64,7 @@ import VIDEO_MIME_TYPES_SUPPORTED from "../../environment/videoMimeTypesSupport" import './appGroupCallsManager'; import appGroupCallsManager from "./appGroupCallsManager"; import appReactionsManager from "./appReactionsManager"; +import { getRestrictionReason, isRestricted } from "../../helpers/restrictions"; //console.trace('include'); // TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках @@ -2831,8 +2832,10 @@ export class AppMessagesManager { } }; + const isRestricted = this.isRestricted(message as any); + let entities = (message as Message.message).totalEntities; - if((message as Message.message).media) { + if((message as Message.message).media && !isRestricted) { assumeType(message); let usingFullAlbum = true; if(message.grouped_id) { @@ -2953,6 +2956,11 @@ export class AppMessagesManager { } } + if(isRestricted) { + text = getRestrictionReason((message as Message.message).restriction_reason).text; + entities = []; + } + if(text) { text = limitSymbols(text, 100); @@ -3616,7 +3624,18 @@ export class AppMessagesManager { return this.searchesStorage[peerId][inputFilter]; } - public getSearchCounters(peerId: PeerId, filters: MessagesFilter[], canCache = true) { + public getSearchCounters(peerId: PeerId, filters: MessagesFilter[], canCache = true): Promise { + if(appPeersManager.isRestricted(peerId)) { + return Promise.resolve(filters.map((filter) => { + return { + _: 'messages.searchCounter', + pFlags: {}, + filter: filter, + count: 0 + }; + })); + } + const func = (canCache ? apiManager.invokeApiCacheable : apiManager.invokeApi).bind(apiManager); return func('messages.getSearchCounters', { peer: appPeersManager.getInputPeerById(peerId), @@ -3778,6 +3797,15 @@ export class AppMessagesManager { offset_id_offset: number, history: MyMessage[] }> { + if(appPeersManager.isRestricted(peerId)) { + return Promise.resolve({ + count: 0, + offset_id_offset: 0, + next_rate: undefined, + history: [] + }); + } + if(!query) query = ''; if(!inputFilter) inputFilter = {_: 'inputMessagesFilterEmpty'}; if(limit === undefined) limit = 20; @@ -5260,6 +5288,10 @@ export class AppMessagesManager { } public canSendToPeer(peerId: PeerId, threadId?: number, action: ChatRights = 'send_messages') { + if(appPeersManager.isRestricted(peerId)) { + return false; + } + if(peerId.isAnyChat()) { //const isChannel = appPeersManager.isChannel(peerId); const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId()); @@ -5482,6 +5514,11 @@ export class AppMessagesManager { peerTypeNotifySettings: PeerNotifySettings }> = {}) { const peerId = this.getMessagePeer(message); + + if(appPeersManager.isRestricted(peerId)) { + return; + } + const isAnyChat = peerId.isAnyChat(); const notification: NotifyOptions = {}; const peerString = appPeersManager.getPeerString(peerId); @@ -5608,6 +5645,10 @@ export class AppMessagesManager { return peerId.isAnyChat() && !appChatsManager.isInChat(peerId.toChatId()); } + public isRestricted(message: Message.message) { + return !!(message.restriction_reason && isRestricted(message.restriction_reason)); + } + public async getNewHistory(peerId: PeerId, threadId?: number) { if(!this.isFetchIntervalNeeded(peerId)) { return; @@ -5641,6 +5682,20 @@ export class AppMessagesManager { public getHistory(peerId: PeerId, maxId = 0, limit: number, backLimit?: number, threadId?: number): Promise | HistoryResult { const historyStorage = this.getHistoryStorage(peerId, threadId); + if(appPeersManager.isRestricted(peerId)) { + const first = historyStorage.history.first; + first.setEnd(SliceEnd.Both); + + const slice = first.slice(0, 0); + slice.setEnd(SliceEnd.Both); + + return { + count: 0, + history: slice, + offsetIdOffset: 0 + }; + } + let offset = 0; /* let offsetFound = true; diff --git a/src/lib/appManagers/appPeersManager.ts b/src/lib/appManagers/appPeersManager.ts index ecbe6c7f..dd49ef06 100644 --- a/src/lib/appManagers/appPeersManager.ts +++ b/src/lib/appManagers/appPeersManager.ts @@ -19,6 +19,7 @@ import appChatsManager from "./appChatsManager"; import appUsersManager from "./appUsersManager"; import I18n from '../langPack'; import { NULL_PEER_ID } from "../mtproto/mtproto_config"; +import { getRestrictionReason } from "../../helpers/restrictions"; // https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC /* @@ -48,11 +49,15 @@ export class AppPeersManager { } public getPeerPhoto(peerId: PeerId): UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto { + if(this.isRestricted(peerId)) { + return; + } + const photo = peerId.isUser() ? appUsersManager.getUserPhoto(peerId.toUserId()) : appChatsManager.getChatPhoto(peerId.toChatId()); - return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : null; + return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : undefined; } public getPeerMigratedTo(peerId: PeerId) { @@ -187,6 +192,20 @@ export class AppPeersManager { return !this.isUser(peerId); } + public isRestricted(peerId: PeerId) { + return peerId.isUser() ? appUsersManager.isRestricted(peerId.toUserId()) : appChatsManager.isRestricted(peerId.toChatId()); + } + + public getRestrictionReasonText(peerId: PeerId) { + const peer: Chat.channel | User.user = this.getPeer(peerId); + const reason = peer.restriction_reason ? getRestrictionReason(peer.restriction_reason) : undefined; + if(reason) { + return reason.text; + } else { + return peerId.isUser() ? 'This user is restricted' : 'This chat is restricted'; + } + } + /* public getInputPeer(peerString: string): InputPeer { var firstChar = peerString.charAt(0); var peerParams = peerString.substr(1).split('_'); diff --git a/src/lib/appManagers/appProfileManager.ts b/src/lib/appManagers/appProfileManager.ts index affd19fb..f9930a82 100644 --- a/src/lib/appManagers/appProfileManager.ts +++ b/src/lib/appManagers/appProfileManager.ts @@ -178,10 +178,6 @@ export class AppProfileManager { userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId}); } - if(userFull.about !== undefined) { - userFull.rAbout = RichTextProcessor.wrapRichText(userFull.about, {noLinebreaks: true}); - } - appNotificationsManager.savePeerSettings({ peerId, settings: userFull.notify_settings diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 9f550fa2..4cf4f06b 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -17,6 +17,7 @@ import cleanUsername from "../../helpers/cleanUsername"; import { formatFullSentTimeRaw, tsNow } from "../../helpers/date"; import { formatPhoneNumber } from "../../helpers/formatPhoneNumber"; import { safeReplaceObject, isObject } from "../../helpers/object"; +import { isRestricted } from "../../helpers/restrictions"; import { Chat, InputContact, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus, InputGeoPoint } from "../../layer"; import I18n, { i18n, LangPackKey } from "../langPack"; //import apiManager from '../mtproto/apiManager'; @@ -1016,6 +1017,13 @@ export class AppUsersManager { }); }); } + + public isRestricted(userId: UserId) { + const user: MTUser.user = this.getUser(userId); + const restrictionReasons = user.restriction_reason; + + return !!(user.pFlags.restricted && restrictionReasons && isRestricted(restrictionReasons)); + } } const appUsersManager = new AppUsersManager(); diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index ca5493b4..e07549bd 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -33,6 +33,7 @@ import { pause } from '../../helpers/schedulers/pause'; import IS_WEBP_SUPPORTED from '../../environment/webpSupport'; import type { ApiError } from './apiManager'; import { MTAppConfig } from './appConfig'; +import { ignoreRestrictionReasons } from '../../helpers/restrictions'; type Task = { taskId: number, @@ -699,12 +700,13 @@ export class ApiManagerProxy extends CryptoWorkerMethods { public getAppConfig(overwrite?: boolean) { if(rootScope.appConfig && !overwrite) return rootScope.appConfig; if(this.getAppConfigPromise && !overwrite) return this.getAppConfigPromise; - const promise: Promise = this.getAppConfigPromise = this.invokeApi('help.getAppConfig').then(config => { + const promise: Promise = this.getAppConfigPromise = this.invokeApi('help.getAppConfig').then((config: MTAppConfig) => { if(this.getAppConfigPromise !== promise) { return this.getAppConfigPromise; } rootScope.appConfig = config; + ignoreRestrictionReasons(config.ignore_restriction_reasons ?? []); return config; }); diff --git a/src/scripts/in/schema_additional_params.json b/src/scripts/in/schema_additional_params.json index 008d7ad9..0e2c97be 100644 --- a/src/scripts/in/schema_additional_params.json +++ b/src/scripts/in/schema_additional_params.json @@ -112,11 +112,6 @@ {"name": "mid", "type": "number"}, {"name": "pFlags", "type": "{}"} ] -}, { - "predicate": "userFull", - "params": [ - {"name": "rAbout", "type": "string"} - ] }, { "predicate": "messageEntityEmoji", "params": [