开篇废话
最近一朋友问了这个问题,研究了一下安排了一个看上去比较稳的方案。
由于使用的是官方客户端 + hook 方式,理论上风险比 userbot 低非常多。
(如果使用 userbot 可能登录的那一刻就炸号了)
所以个人认为是最稳的方案。
太长不看
点 击 安 装(需要先安装 Tampermonkey)
然后访问网页版 Telegram:
Telegram Web A version
A version 解锁了 媒体资源下载 + 任意文本复制
K version 解锁了 媒体资源下载,并且这个下载是直接下载而非像 MEGA 一样的先缓存到网页的那种。
^ Tampermonkey 可以在浏览器商店自行下载,这里不再提供安装教程。
思路
可以先看看前两篇文章看下我的思路:
原始思路
首先就是打开媒体资源,右上角会少掉好几个按钮,下载和转发没掉了,我们切入点就是找这附近的代码。
目测 zoom-in / zoom-out 代码肯定在 download 附近:
我们在F12 -> sources 切各种 js 搜索,最终找到了 3779 如图所示的代码区域(代码会更新,请以实际情况为准)
然后左边的 tab 启用 overrides 强行盖本地的资源过去,修改代码就 ok 了
然后注销掉 pwa session(unregister)如图所示, ctrl + F5 / cmd + shift + R 忽略缓存刷新网页 patch 就生效了。
于是下载按钮就正常加载了,功能也是正常的。
当然每隔一段时间就要修改肯定不怎么爽的,于是我们寻找更激进的 hook 办法:
hook 思路
还是老朋友 Object.defineProperty
/ new Proxy
来 hook 。
我们先看源代码,给刚才找到的判断下个断点看看:
(此处 override 的代码需要直接删除,否则跳转不到 webpack 的原始代码)
于是可以看到在 ../../global/selectors
的代码完成了判断消息是否做保护的操作:
export function selectIsMessageProtected<T extends GlobalState>(global: T, message?: ApiMessage) {
return Boolean(message && (message.isProtected || selectIsChatProtected(global, message.chatId)));
}
export function selectIsChatProtected<T extends GlobalState>(global: T, chatId: string) {
return selectChat(global, chatId)?.isProtected || false;
}
export function selectHasProtectedMessage<T extends GlobalState>(global: T, chatId: string, messageIds?: number[]) {
if (selectChat(global, chatId)?.isProtected) {
return true;
}
if (!messageIds) {
return false;
}
const messages = selectChatMessages(global, chatId);
return messageIds.some((messageId) => messages[messageId]?.isProtected);
}
代码出处我们已经知道了,但是我们能做的有限,因为代码都是闭包(大概?)所以只能采取更激进的办法,在这个例子我们可以知道,带保护的消息被授予了 isProtected
为真的属性,有没有一种办法让任意的对象(Object)的 .isProtected
都为 false 呢?
答案是有的,还是我们的老朋友 Object.defineProperty
,只不过这次我们使用了更全局,更危险的办法来安排,只不过这次没有明确的目标,只能劫持所有的 Object.isProtected 了。
Object.defineProperty(Object.prototype, 'isProtected', {
get: function () {
return false;
},
set: function () {
return true;
},
configurable: false,
});
Object.prototype
是 JS 运行时所有 Object 的 prototype ,因此这边 hook 就对应了全局的(和 ABEMA 那次的不太一样)
总结
简单来说就是 js 万物都可以重定义,所以不用太惊讶。
完