Full seamless login support
This commit is contained in:
parent
7097d0c5af
commit
1f1cb9c489
|
@ -3982,92 +3982,15 @@ export default class ChatBubbles {
|
|||
const {mid} = message;
|
||||
const {url, button_id} = button;
|
||||
|
||||
const openWindow = (url: string) => {
|
||||
window.open(url, '_blank');
|
||||
};
|
||||
|
||||
const onUrlAuthResultAccepted = (urlAuthResult: UrlAuthResult.urlAuthResultAccepted) => {
|
||||
openWindow(urlAuthResult.url);
|
||||
};
|
||||
|
||||
const onUrlAuthResult = async(urlAuthResult: UrlAuthResult): Promise<void> => {
|
||||
if(urlAuthResult._ === 'urlAuthResultRequest') {
|
||||
const b = document.createElement('b');
|
||||
b.append(urlAuthResult.domain);
|
||||
const peerTitle = await wrapPeerTitle({peerId: rootScope.myId});
|
||||
const botPeerTitle = await wrapPeerTitle({peerId: urlAuthResult.bot.id.toPeerId()});
|
||||
|
||||
const logInCheckbox: PopupPeerCheckboxOptions = {
|
||||
text: 'OpenUrlOption1',
|
||||
textArgs: [b.cloneNode(true), peerTitle],
|
||||
checked: true
|
||||
};
|
||||
|
||||
const allowMessagesCheckbox: PopupPeerCheckboxOptions = urlAuthResult.pFlags.request_write_access ? {
|
||||
text: 'OpenUrlOption2',
|
||||
textArgs: [botPeerTitle],
|
||||
checked: true
|
||||
} : undefined;
|
||||
|
||||
const checkboxes: PopupPeerCheckboxOptions[] = [
|
||||
logInCheckbox,
|
||||
allowMessagesCheckbox
|
||||
];
|
||||
|
||||
const confirmationPromise = confirmationPopup({
|
||||
titleLangKey: 'OpenUrlTitle',
|
||||
button: {
|
||||
langKey: 'Open'
|
||||
},
|
||||
descriptionLangKey: 'OpenUrlAlert2',
|
||||
descriptionLangArgs: [b],
|
||||
checkboxes: checkboxes.filter(Boolean)
|
||||
});
|
||||
|
||||
if(allowMessagesCheckbox) {
|
||||
logInCheckbox.checkboxField.input.addEventListener('change', () => {
|
||||
const disabled = !logInCheckbox.checkboxField.checked;
|
||||
allowMessagesCheckbox.checkboxField.toggleDisability(disabled);
|
||||
|
||||
if(disabled) {
|
||||
allowMessagesCheckbox.checkboxField.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const [logInChecked, allowMessagesChecked] = await confirmationPromise;
|
||||
|
||||
if(!logInChecked) {
|
||||
openWindow(url);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await this.managers.appMessagesManager.acceptUrlAuth(
|
||||
peerId,
|
||||
mid,
|
||||
url,
|
||||
button_id,
|
||||
allowMessagesChecked
|
||||
);
|
||||
|
||||
return onUrlAuthResult(result);
|
||||
} else if(urlAuthResult._ === 'urlAuthResultAccepted') {
|
||||
onUrlAuthResultAccepted(urlAuthResult);
|
||||
} else {
|
||||
openWindow(url);
|
||||
}
|
||||
};
|
||||
|
||||
attachClickEvent(buttonEl, () => {
|
||||
const toggle = toggleDisability([buttonEl], true);
|
||||
this.managers.appMessagesManager.requestUrlAuth(
|
||||
this.chat.appImManager.handleUrlAuth({
|
||||
peerId,
|
||||
mid,
|
||||
url,
|
||||
button_id
|
||||
).then((urlAuthResult) => {
|
||||
buttonId: button_id
|
||||
}).then(() => {
|
||||
toggle();
|
||||
onUrlAuthResult(urlAuthResult);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
|
|
@ -167,10 +167,7 @@ export default class AppActiveSessionsTab extends SliderSuperTabEventable {
|
|||
}
|
||||
|
||||
onCloseAfterTimeout() {
|
||||
if(this.menuElement) {
|
||||
this.menuElement.remove();
|
||||
}
|
||||
|
||||
this.menuElement?.remove();
|
||||
return super.onCloseAfterTimeout();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import {formatDateAccordingToTodayNew} from '../../../helpers/date';
|
||||
import {attachClickEvent} from '../../../helpers/dom/clickEvent';
|
||||
import findUpClassName from '../../../helpers/dom/findUpClassName';
|
||||
import toggleDisability from '../../../helpers/dom/toggleDisability';
|
||||
import {WebAuthorization} from '../../../layer';
|
||||
import AvatarElement from '../../avatar';
|
||||
import Button from '../../button';
|
||||
import confirmationPopup from '../../confirmationPopup';
|
||||
import Row from '../../row';
|
||||
import SettingSection from '../../settingSection';
|
||||
import {SliderSuperTabEventable} from '../../sliderTab';
|
||||
import wrapPeerTitle from '../../wrappers/peerTitle';
|
||||
|
||||
export default class AppActiveWebSessionsTab extends SliderSuperTabEventable {
|
||||
public async init(sessions: WebAuthorization[]) {
|
||||
this.container.classList.add('active-sessions-container');
|
||||
this.setTitle('WebSessionsTitle');
|
||||
|
||||
const Session = async(auth: WebAuthorization) => {
|
||||
const peerId = auth.bot_id.toPeerId();
|
||||
const row = new Row({
|
||||
title: await wrapPeerTitle({peerId}),
|
||||
subtitle: [auth.ip, auth.region].join(' - '),
|
||||
clickable: true,
|
||||
titleRight: formatDateAccordingToTodayNew(new Date(Math.max(auth.date_active, auth.date_created) * 1000))
|
||||
});
|
||||
|
||||
const media = row.createMedia('big');
|
||||
const avatar = new AvatarElement();
|
||||
avatar.classList.add('avatar-48');
|
||||
await avatar.updateWithOptions({peerId});
|
||||
media.append(avatar);
|
||||
|
||||
row.container.dataset.hash = '' + auth.hash;
|
||||
row.container.dataset.peerId = '' + peerId;
|
||||
|
||||
row.midtitle.textContent = [auth.domain, auth.browser, auth.platform].filter(Boolean).join(', ');
|
||||
|
||||
return row;
|
||||
};
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
caption: 'ClearOtherWebSessionsHelp'
|
||||
});
|
||||
|
||||
const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'TerminateAllWebSessions'});
|
||||
|
||||
attachClickEvent(btnTerminate, async() => {
|
||||
await confirmationPopup({
|
||||
descriptionLangKey: 'AreYouSureWebSessions',
|
||||
button: {
|
||||
langKey: 'Disconnect',
|
||||
isDanger: true
|
||||
}
|
||||
});
|
||||
|
||||
const toggle = toggleDisability([btnTerminate], true);
|
||||
this.managers.appSeamlessLoginManager.resetWebAuthorizations().then(() => {
|
||||
this.close();
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
section.content.append(btnTerminate);
|
||||
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
|
||||
{
|
||||
const section = new SettingSection({
|
||||
name: 'OtherWebSessions',
|
||||
caption: 'TerminateWebSessionInfo'
|
||||
});
|
||||
|
||||
const rows = await Promise.all(sessions.map(Session));
|
||||
section.content.append(...rows.map((row) => row.container));
|
||||
|
||||
let leftLength = rows.length;
|
||||
attachClickEvent(section.content, async(e) => {
|
||||
const row = findUpClassName(e.target, 'row');
|
||||
if(!row) {
|
||||
return;
|
||||
}
|
||||
|
||||
await confirmationPopup({
|
||||
descriptionLangKey: 'TerminateWebSessionText',
|
||||
descriptionLangArgs: [await wrapPeerTitle({peerId: row.dataset.peerId.toPeerId()})],
|
||||
button: {
|
||||
langKey: 'Disconnect',
|
||||
isDanger: true
|
||||
}
|
||||
});
|
||||
|
||||
const hash = row.dataset.hash;
|
||||
row.classList.add('is-disabled');
|
||||
this.managers.appSeamlessLoginManager.resetWebAuthorization(hash).then(() => {
|
||||
if(!--leftLength) {
|
||||
this.close();
|
||||
} else {
|
||||
row.remove();
|
||||
}
|
||||
});
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
this.scrollable.append(section.container);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import SliderSuperTab, {SliderSuperTabEventable} from '../../sliderTab';
|
||||
import Row from '../../row';
|
||||
import {AccountPassword, Authorization, InputPrivacyKey, Updates} from '../../../layer';
|
||||
import {AccountPassword, Authorization, InputPrivacyKey, Updates, WebAuthorization} from '../../../layer';
|
||||
import AppPrivacyPhoneNumberTab from './privacy/phoneNumber';
|
||||
import AppTwoStepVerificationTab from './2fa';
|
||||
import AppTwoStepVerificationEnterPasswordTab from './2fa/enterPassword';
|
||||
|
@ -33,16 +33,21 @@ import noop from '../../../helpers/noop';
|
|||
import {toastNew} from '../../toast';
|
||||
import AppPrivacyVoicesTab from './privacy/voices';
|
||||
import SettingSection from '../../settingSection';
|
||||
import AppActiveWebSessionsTab from './activeWebSessions';
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
private activeSessionsRow: Row;
|
||||
private authorizations: Authorization.authorization[];
|
||||
|
||||
private websitesRow: Row;
|
||||
private websites: WebAuthorization[];
|
||||
|
||||
public static getInitArgs(fromTab: SliderSuperTab) {
|
||||
return {
|
||||
appConfig: fromTab.managers.apiManager.getAppConfig(),
|
||||
globalPrivacy: fromTab.managers.appPrivacyManager.getGlobalPrivacySettings(),
|
||||
contentSettings: fromTab.managers.apiManager.invokeApi('account.getContentSettings')
|
||||
contentSettings: fromTab.managers.apiManager.invokeApi('account.getContentSettings'),
|
||||
webAuthorizations: fromTab.managers.appSeamlessLoginManager.getWebAuthorizations()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,6 +56,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||
this.setTitle('PrivacySettings');
|
||||
|
||||
const SUBTITLE: LangPackKey = 'Loading';
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
{
|
||||
const section = new SettingSection({noDelimiter: true, caption: 'SessionsInfo'});
|
||||
|
@ -113,7 +119,22 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||
});
|
||||
activeSessionsRow.freezed = true;
|
||||
|
||||
section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionsRow.container);
|
||||
const websitesRow = this.websitesRow = new Row({
|
||||
icon: 'mention',
|
||||
titleLangKey: 'OtherWebSessions',
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
const tab = this.slider.createTab(AppActiveWebSessionsTab);
|
||||
tab.eventListener.addEventListener('destroy', () => {
|
||||
this.updateActiveWebsites();
|
||||
});
|
||||
tab.open(this.websites);
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
websitesRow.freezed = true;
|
||||
|
||||
section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionsRow.container, websitesRow.container);
|
||||
this.scrollable.append(section.container);
|
||||
|
||||
const setBlockedCount = (count: number) => {
|
||||
|
@ -152,6 +173,7 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||
});
|
||||
|
||||
this.updateActiveSessions();
|
||||
promises.push(this.updateActiveWebsites(p.webAuthorizations));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -271,8 +293,6 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||
});
|
||||
}
|
||||
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
{
|
||||
const section = new SettingSection({name: 'NewChatsFromNonContacts', caption: 'ArchiveAndMuteInfo'});
|
||||
|
||||
|
@ -441,15 +461,35 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
|||
this.scrollable.append(section.container);
|
||||
}
|
||||
|
||||
// {
|
||||
// const section = new SettingSection({
|
||||
// name: 'OtherWebSessions'
|
||||
// });
|
||||
|
||||
// const row = new Row({
|
||||
|
||||
// });
|
||||
|
||||
// this.scrollable.append(section.container);
|
||||
// }
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
public updateActiveSessions() {
|
||||
this.managers.apiManager.invokeApi('account.getAuthorizations').then((auths) => {
|
||||
return this.managers.apiManager.invokeApi('account.getAuthorizations').then((auths) => {
|
||||
this.activeSessionsRow.freezed = false;
|
||||
this.authorizations = auths.authorizations;
|
||||
_i18n(this.activeSessionsRow.subtitle, 'Privacy.Devices', [this.authorizations.length]);
|
||||
// console.log('auths', auths);
|
||||
});
|
||||
}
|
||||
|
||||
public updateActiveWebsites(promise = this.managers.appSeamlessLoginManager.getWebAuthorizations()) {
|
||||
return promise.then((authorizations) => {
|
||||
this.websitesRow.freezed = false;
|
||||
this.websites = authorizations;
|
||||
_i18n(this.websitesRow.subtitle, 'Privacy.Websites', [this.websites.length]);
|
||||
this.websitesRow.container.classList.toggle('hide', !this.websites.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ const App = {
|
|||
version: process.env.VERSION,
|
||||
versionFull: process.env.VERSION_FULL,
|
||||
build: +process.env.BUILD,
|
||||
langPackVersion: '0.7.5',
|
||||
langPackVersion: '0.7.6',
|
||||
langPack: 'webk',
|
||||
langPackCode: 'en',
|
||||
domains: MAIN_DOMAINS,
|
||||
|
|
|
@ -14,10 +14,11 @@ export default function addAnchorListener<Params extends {pathnameParams?: any,
|
|||
protocol?: 'tg',
|
||||
callback: (params: Params, element?: HTMLAnchorElement) => boolean | any,
|
||||
noPathnameParams?: boolean,
|
||||
noUriParams?: boolean
|
||||
noUriParams?: boolean,
|
||||
noCancelEvent?: boolean
|
||||
}) {
|
||||
(window as any)[(options.protocol ? options.protocol + '_' : '') + options.name] = (element?: HTMLAnchorElement/* , e: Event */) => {
|
||||
cancelEvent(null);
|
||||
!options.noCancelEvent && cancelEvent(null);
|
||||
|
||||
let href = element.href;
|
||||
let pathnameParams: any[];
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
export default function cancelEvent(event: Event) {
|
||||
event = event || window.event;
|
||||
export default function cancelEvent(event?: Event) {
|
||||
event ||= window.event;
|
||||
if(event) {
|
||||
// @ts-ignore
|
||||
event = event.originalEvent || event;
|
||||
|
|
12
src/lang.ts
12
src/lang.ts
|
@ -98,6 +98,10 @@ const lang = {
|
|||
'one_value': '%1$d device',
|
||||
'other_value': '%1$d devices'
|
||||
},
|
||||
'Privacy.Websites': {
|
||||
'one_value': '%1$d website',
|
||||
'other_value': '%1$d websites'
|
||||
},
|
||||
'Privacy.SensitiveContent': 'Sensitive Content',
|
||||
'PrivacyModal.Search.Placeholder': 'Add Users or Groups...',
|
||||
'Permissions.NoExceptions': 'No exceptions',
|
||||
|
@ -855,6 +859,14 @@ const lang = {
|
|||
'EditTopicHideInfo': 'If the \'General\' topic is hidden, group members can pull down in the topic list to view it.',
|
||||
'OpenUrlOption1': 'Log in to %1$s as **%2$s**',
|
||||
'OpenUrlOption2': 'Allow **%1$s** to send me messages',
|
||||
'OtherWebSessions': 'Connected websites',
|
||||
'WebSessionsTitle': 'Logged In with Telegram',
|
||||
'TerminateWebSessionText': 'Are you sure you want to disconnect %1$s?',
|
||||
'Disconnect': 'Disconnect',
|
||||
'TerminateAllWebSessions': 'Disconnect All Websites',
|
||||
'AreYouSureWebSessions': 'Are you sure you want to disconnect all websites where you logged in with Telegram?',
|
||||
'ClearOtherWebSessionsHelp': 'You can log in on websites that support signing in with Telegram.',
|
||||
'TerminateWebSessionInfo': 'Tap to disconnect from your Telegram account.',
|
||||
|
||||
// * macos
|
||||
'AccountSettings.Filters': 'Chat Folders',
|
||||
|
|
|
@ -27,9 +27,9 @@ import {MOUNT_CLASS_TO} from '../../config/debug';
|
|||
import appNavigationController from '../../components/appNavigationController';
|
||||
import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';
|
||||
import I18n, {i18n, join, LangPackKey} from '../langPack';
|
||||
import {ChatFull, ChatInvite, ChatParticipant, ChatParticipants, Message, MessageAction, MessageMedia, SendMessageAction, User, Chat as MTChat} from '../../layer';
|
||||
import {ChatFull, ChatInvite, ChatParticipant, ChatParticipants, Message, MessageAction, MessageMedia, SendMessageAction, User, Chat as MTChat, UrlAuthResult} from '../../layer';
|
||||
import PeerTitle from '../../components/peerTitle';
|
||||
import PopupPeer from '../../components/popups/peer';
|
||||
import PopupPeer, {PopupPeerCheckboxOptions} from '../../components/popups/peer';
|
||||
import blurActiveElement from '../../helpers/dom/blurActiveElement';
|
||||
import cancelEvent from '../../helpers/dom/cancelEvent';
|
||||
import disableTransition from '../../helpers/dom/disableTransition';
|
||||
|
@ -98,6 +98,8 @@ import {MiddleEllipsisElement} from '../../components/middleEllipsis';
|
|||
import addAnchorListener from '../../helpers/addAnchorListener';
|
||||
import parseUriParams from '../../helpers/string/parseUriParams';
|
||||
import getMessageThreadId from './utils/messages/getMessageThreadId';
|
||||
import findUpTag from '../../helpers/dom/findUpTag';
|
||||
import {MTAppConfig} from '../mtproto/appConfig';
|
||||
|
||||
export type ChatSavedPosition = {
|
||||
mids: number[],
|
||||
|
@ -783,6 +785,149 @@ export class AppImManager extends EventListenerBase<{
|
|||
|
||||
this.onHashChange(true);
|
||||
this.attachKeydownListener();
|
||||
this.handleAutologinDomains();
|
||||
}
|
||||
|
||||
public handleUrlAuth(options: {
|
||||
peerId?: PeerId,
|
||||
mid?: number,
|
||||
buttonId?: number,
|
||||
url: string
|
||||
}) {
|
||||
const {peerId, mid, buttonId, url} = options;
|
||||
|
||||
const openWindow = (url: string) => {
|
||||
window.open(url, '_blank');
|
||||
};
|
||||
|
||||
const onUrlAuthResultAccepted = (urlAuthResult: UrlAuthResult.urlAuthResultAccepted) => {
|
||||
openWindow(urlAuthResult.url);
|
||||
};
|
||||
|
||||
const onUrlAuthResult = async(urlAuthResult: UrlAuthResult): Promise<void> => {
|
||||
if(urlAuthResult._ === 'urlAuthResultRequest') {
|
||||
const b = document.createElement('b');
|
||||
b.append(urlAuthResult.domain);
|
||||
const peerTitle = await wrapPeerTitle({peerId: rootScope.myId});
|
||||
const botPeerTitle = await wrapPeerTitle({peerId: urlAuthResult.bot.id.toPeerId()});
|
||||
|
||||
const logInCheckbox: PopupPeerCheckboxOptions = {
|
||||
text: 'OpenUrlOption1',
|
||||
textArgs: [b.cloneNode(true), peerTitle],
|
||||
checked: true
|
||||
};
|
||||
|
||||
const allowMessagesCheckbox: PopupPeerCheckboxOptions = urlAuthResult.pFlags.request_write_access ? {
|
||||
text: 'OpenUrlOption2',
|
||||
textArgs: [botPeerTitle],
|
||||
checked: true
|
||||
} : undefined;
|
||||
|
||||
const checkboxes: PopupPeerCheckboxOptions[] = [
|
||||
logInCheckbox,
|
||||
allowMessagesCheckbox
|
||||
];
|
||||
|
||||
const confirmationPromise = confirmationPopup({
|
||||
titleLangKey: 'OpenUrlTitle',
|
||||
button: {
|
||||
langKey: 'Open'
|
||||
},
|
||||
descriptionLangKey: 'OpenUrlAlert2',
|
||||
descriptionLangArgs: [b],
|
||||
checkboxes: checkboxes.filter(Boolean)
|
||||
});
|
||||
|
||||
if(allowMessagesCheckbox) {
|
||||
logInCheckbox.checkboxField.input.addEventListener('change', () => {
|
||||
const disabled = !logInCheckbox.checkboxField.checked;
|
||||
allowMessagesCheckbox.checkboxField.toggleDisability(disabled);
|
||||
|
||||
if(disabled) {
|
||||
allowMessagesCheckbox.checkboxField.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const [logInChecked, allowMessagesChecked] = await confirmationPromise;
|
||||
|
||||
if(!logInChecked) {
|
||||
openWindow(url);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await this.managers.appSeamlessLoginManager.acceptUrlAuth(
|
||||
url,
|
||||
peerId,
|
||||
mid,
|
||||
buttonId,
|
||||
allowMessagesChecked
|
||||
);
|
||||
|
||||
return onUrlAuthResult(result);
|
||||
} else if(urlAuthResult._ === 'urlAuthResultAccepted') {
|
||||
onUrlAuthResultAccepted(urlAuthResult);
|
||||
} else {
|
||||
openWindow(url);
|
||||
}
|
||||
};
|
||||
|
||||
return this.managers.appSeamlessLoginManager.requestUrlAuth(
|
||||
url,
|
||||
peerId,
|
||||
mid,
|
||||
buttonId
|
||||
).then((urlAuthResult) => {
|
||||
onUrlAuthResult(urlAuthResult);
|
||||
});
|
||||
}
|
||||
|
||||
private handleAutologinDomains() {
|
||||
let appConfig: MTAppConfig;
|
||||
rootScope.addEventListener('app_config', (_appConfig) => {
|
||||
appConfig = _appConfig;
|
||||
});
|
||||
|
||||
const onAnchorClick = (element: HTMLAnchorElement) => {
|
||||
const url = new URL(element.href);
|
||||
if(appConfig.url_auth_domains.includes(url.hostname)) {
|
||||
this.handleUrlAuth({url: element.href});
|
||||
cancelEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!appConfig.autologin_token || !appConfig.autologin_domains) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalUrl = element.dataset.originalUrl ??= element.href;
|
||||
if(appConfig.autologin_domains.includes(url.hostname)) {
|
||||
url.searchParams.set('autologin_token', appConfig.autologin_token);
|
||||
element.href = url.toString();
|
||||
|
||||
setTimeout(() => {
|
||||
element.href = originalUrl;
|
||||
delete element.dataset.originalUrl;
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
const anchor = findUpTag(e.target as HTMLElement, 'A') as HTMLAnchorElement;
|
||||
if(anchor?.href) {
|
||||
onAnchorClick(anchor);
|
||||
}
|
||||
});
|
||||
|
||||
// addAnchorListener({
|
||||
// name: 'handleUrlClick',
|
||||
// callback: (_, element) => {
|
||||
// onAnchorClick(element);
|
||||
// },
|
||||
// noCancelEvent: true,
|
||||
// noPathnameParams: true,
|
||||
// noUriParams: true
|
||||
// });
|
||||
}
|
||||
|
||||
private getStackFromElement(element: HTMLElement) {
|
||||
|
|
|
@ -6399,31 +6399,4 @@ export class AppMessagesManager extends AppManager {
|
|||
send_as: this.appPeersManager.getInputPeerById(sendAsPeerId)
|
||||
});
|
||||
}
|
||||
|
||||
public requestUrlAuth(peerId: PeerId, mid: number, url: string, buttonId: number) {
|
||||
return this.apiManager.invokeApi('messages.requestUrlAuth', {
|
||||
button_id: buttonId,
|
||||
msg_id: getServerMessageId(mid),
|
||||
peer: this.appPeersManager.getInputPeerById(peerId),
|
||||
url
|
||||
}).then((urlAuthResult) => {
|
||||
if(urlAuthResult._ === 'urlAuthResultRequest') {
|
||||
this.appUsersManager.saveApiUser(urlAuthResult.bot);
|
||||
}
|
||||
|
||||
return urlAuthResult;
|
||||
});
|
||||
}
|
||||
|
||||
public acceptUrlAuth(peerId: PeerId, mid: number, url: string, buttonId: number, writeAllowed?: boolean) {
|
||||
return this.apiManager.invokeApi('messages.acceptUrlAuth', {
|
||||
button_id: buttonId,
|
||||
msg_id: getServerMessageId(mid),
|
||||
peer: this.appPeersManager.getInputPeerById(peerId),
|
||||
url,
|
||||
write_allowed: writeAllowed
|
||||
}).then((urlAuthResult) => {
|
||||
return urlAuthResult as Exclude<UrlAuthResult, UrlAuthResult.urlAuthResultRequest>;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import {UrlAuthResult} from '../../layer';
|
||||
import {AppManager} from './manager';
|
||||
import getServerMessageId from './utils/messageId/getServerMessageId';
|
||||
|
||||
export default class AppSeamlessLoginManager extends AppManager {
|
||||
public requestUrlAuth(url: string, peerId?: PeerId, mid?: number, buttonId?: number) {
|
||||
return this.apiManager.invokeApi('messages.requestUrlAuth', {
|
||||
button_id: buttonId,
|
||||
msg_id: mid ? getServerMessageId(mid) : undefined,
|
||||
peer: peerId ? this.appPeersManager.getInputPeerById(peerId) : undefined,
|
||||
url
|
||||
}).then((urlAuthResult) => {
|
||||
if(urlAuthResult._ === 'urlAuthResultRequest') {
|
||||
this.appUsersManager.saveApiUser(urlAuthResult.bot);
|
||||
}
|
||||
|
||||
return urlAuthResult;
|
||||
});
|
||||
}
|
||||
|
||||
public acceptUrlAuth(url: string, peerId?: PeerId, mid?: number, buttonId?: number, writeAllowed?: boolean) {
|
||||
return this.apiManager.invokeApi('messages.acceptUrlAuth', {
|
||||
button_id: buttonId,
|
||||
msg_id: mid ? getServerMessageId(mid) : undefined,
|
||||
peer: peerId ? this.appPeersManager.getInputPeerById(peerId) : undefined,
|
||||
url,
|
||||
write_allowed: writeAllowed
|
||||
}).then((urlAuthResult) => {
|
||||
return urlAuthResult as Exclude<UrlAuthResult, UrlAuthResult.urlAuthResultRequest>;
|
||||
});
|
||||
}
|
||||
|
||||
public getWebAuthorizations() {
|
||||
return this.apiManager.invokeApi('account.getWebAuthorizations').then((webAuthorizations) => {
|
||||
this.appUsersManager.saveApiUsers(webAuthorizations.users);
|
||||
return webAuthorizations.authorizations;
|
||||
});
|
||||
}
|
||||
|
||||
public resetWebAuthorization(hash: Long) {
|
||||
return this.apiManager.invokeApi('account.resetWebAuthorization', {
|
||||
hash
|
||||
});
|
||||
}
|
||||
|
||||
public resetWebAuthorizations() {
|
||||
return this.apiManager.invokeApi('account.resetWebAuthorizations');
|
||||
}
|
||||
}
|
|
@ -46,6 +46,7 @@ import filterUnique from '../../helpers/array/filterUnique';
|
|||
import AppWebDocsManager from './appWebDocsManager';
|
||||
import AppPaymentsManager from './appPaymentsManager';
|
||||
import AppAttachMenuBotsManager from './appAttachMenuBotsManager';
|
||||
import AppSeamlessLoginManager from './appSeamlessLoginManager';
|
||||
|
||||
export default function createManagers(appStoragesManager: AppStoragesManager, userId: UserId) {
|
||||
const managers = {
|
||||
|
@ -88,7 +89,8 @@ export default function createManagers(appStoragesManager: AppStoragesManager, u
|
|||
appStateManager: appStateManager,
|
||||
appWebDocsManager: new AppWebDocsManager,
|
||||
appPaymentsManager: new AppPaymentsManager,
|
||||
appAttachMenuBotsManager: new AppAttachMenuBotsManager
|
||||
appAttachMenuBotsManager: new AppAttachMenuBotsManager,
|
||||
appSeamlessLoginManager: new AppSeamlessLoginManager
|
||||
};
|
||||
|
||||
type T = typeof managers;
|
||||
|
|
|
@ -44,6 +44,7 @@ import type {AppUsersManager} from './appUsersManager';
|
|||
import type AppWebDocsManager from './appWebDocsManager';
|
||||
import type {AppWebPagesManager} from './appWebPagesManager';
|
||||
import type AppAttachMenuBotsManager from './appAttachMenuBotsManager';
|
||||
import type AppSeamlessLoginManager from './appSeamlessLoginManager';
|
||||
import type {AppManagers} from './managers';
|
||||
|
||||
export class AppManager {
|
||||
|
@ -88,6 +89,7 @@ export class AppManager {
|
|||
protected appWebDocsManager: AppWebDocsManager;
|
||||
protected appPaymentsManager: AppPaymentsManager;
|
||||
protected appAttachMenuBotsManager: AppAttachMenuBotsManager;
|
||||
protected appSeamlessLoginManager: AppSeamlessLoginManager;
|
||||
|
||||
public clear: (init?: boolean) => void;
|
||||
|
||||
|
|
|
@ -98,6 +98,13 @@ export class ApiManager extends ApiManagerMethods {
|
|||
this.changeTransportType(transportType);
|
||||
});
|
||||
// #endif
|
||||
|
||||
// * Make sure that the used autologin_token is no more than 10000 seconds old
|
||||
// * https://core.telegram.org/api/url-authorization
|
||||
const REFRESH_APP_CONFIG_INTERVAL = (10000 - 30) * 1000;
|
||||
setInterval(() => {
|
||||
this.getAppConfig(true);
|
||||
}, REFRESH_APP_CONFIG_INTERVAL);
|
||||
}
|
||||
|
||||
protected after() {
|
||||
|
|
|
@ -225,6 +225,11 @@ avatar-element {
|
|||
--multiplier: 1.35;
|
||||
}
|
||||
|
||||
&.avatar-36 {
|
||||
--size: 36px;
|
||||
--multiplier: 1.5;
|
||||
}
|
||||
|
||||
&.avatar-35 {
|
||||
--size: 35px;
|
||||
--multiplier: 1.542857;
|
||||
|
|
|
@ -114,7 +114,7 @@ $btn-menu-z-index: 4;
|
|||
font-size: 1rem;
|
||||
backdrop-filter: var(--menu-backdrop-filter);
|
||||
min-width: 11.25rem;
|
||||
max-width: 16.25rem;
|
||||
// max-width: 16.25rem;
|
||||
|
||||
&-old {
|
||||
padding: .5rem 0;
|
||||
|
|
Loading…
Reference in New Issue