Introduce Web Token login (#2129)
This commit is contained in:
parent
7cc64ed6bb
commit
7c3e790eac
13
src/App.tsx
13
src/App.tsx
@ -20,12 +20,14 @@ import LockScreen from './components/main/LockScreen.async';
|
||||
import AppInactive from './components/main/AppInactive';
|
||||
import Transition from './components/ui/Transition';
|
||||
import UiLoader from './components/common/UiLoader';
|
||||
import { parseInitialLocationHash } from './util/routing';
|
||||
// import Test from './components/test/TestNoRedundancy';
|
||||
|
||||
type StateProps = {
|
||||
authState: GlobalState['authState'];
|
||||
isScreenLocked?: boolean;
|
||||
hasPasscode?: boolean;
|
||||
hasWebAuthTokenFailed?: boolean;
|
||||
};
|
||||
|
||||
enum AppScreens {
|
||||
@ -39,6 +41,7 @@ const App: FC<StateProps> = ({
|
||||
authState,
|
||||
isScreenLocked,
|
||||
hasPasscode,
|
||||
hasWebAuthTokenFailed,
|
||||
}) => {
|
||||
const { disconnect } = getActions();
|
||||
|
||||
@ -130,6 +133,15 @@ const App: FC<StateProps> = ({
|
||||
activeKey = AppScreens.auth;
|
||||
}
|
||||
|
||||
if (activeKey !== AppScreens.lock
|
||||
&& activeKey !== AppScreens.inactive
|
||||
&& activeKey !== AppScreens.main
|
||||
&& parseInitialLocationHash()?.tgWebAuthToken
|
||||
&& !hasWebAuthTokenFailed) {
|
||||
page = 'main';
|
||||
activeKey = AppScreens.main;
|
||||
}
|
||||
|
||||
const prevActiveKey = usePrevious(activeKey);
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
@ -169,6 +181,7 @@ export default withGlobal(
|
||||
authState: global.authState,
|
||||
isScreenLocked: global.passcode?.isScreenLocked,
|
||||
hasPasscode: global.passcode?.hasPasscode,
|
||||
hasWebAuthTokenFailed: global.hasWebAuthTokenFailed,
|
||||
};
|
||||
},
|
||||
)(App);
|
||||
|
||||
@ -27,6 +27,12 @@ export function init(_onUpdate: OnApiUpdate) {
|
||||
onUpdate = _onUpdate;
|
||||
}
|
||||
|
||||
export function onWebAuthTokenFailed() {
|
||||
onUpdate({
|
||||
'@type': 'updateWebAuthTokenFailed',
|
||||
});
|
||||
}
|
||||
|
||||
export function onRequestPhoneNumber() {
|
||||
onUpdate(buildAuthStateUpdate('authorizationStateWaitPhoneNumber'));
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
} from '../../../config';
|
||||
import {
|
||||
onRequestPhoneNumber, onRequestCode, onRequestPassword, onRequestRegistration,
|
||||
onAuthError, onAuthReady, onCurrentUserUpdate, onRequestQrCode,
|
||||
onAuthError, onAuthReady, onCurrentUserUpdate, onRequestQrCode, onWebAuthTokenFailed,
|
||||
} from './auth';
|
||||
import { updater } from '../updater';
|
||||
import { setMessageBuilderCurrentUserId } from '../apiBuilders/messages';
|
||||
@ -51,7 +51,7 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
|
||||
onUpdate = _onUpdate;
|
||||
|
||||
const {
|
||||
userAgent, platform, sessionData, isTest, isMovSupported, isWebmSupported, maxBufferSize,
|
||||
userAgent, platform, sessionData, isTest, isMovSupported, isWebmSupported, maxBufferSize, webAuthToken, dcId,
|
||||
} = initialArgs;
|
||||
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
|
||||
|
||||
@ -75,6 +75,7 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
|
||||
useWSS: true,
|
||||
additionalDcsDisabled: IS_TEST,
|
||||
testServers: isTest,
|
||||
dcId,
|
||||
} as any,
|
||||
);
|
||||
|
||||
@ -101,6 +102,8 @@ export async function init(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs)
|
||||
onError: onAuthError,
|
||||
initialMethod: platform === 'iOS' || platform === 'Android' ? 'phoneNumber' : 'qrCode',
|
||||
shouldThrowIfUnauthorized: Boolean(sessionData),
|
||||
webAuthToken,
|
||||
webAuthTokenFailed: onWebAuthTokenFailed,
|
||||
});
|
||||
} catch (err: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
||||
@ -10,6 +10,8 @@ export interface ApiInitialArgs {
|
||||
isMovSupported?: boolean;
|
||||
isWebmSupported?: boolean;
|
||||
maxBufferSize?: number;
|
||||
webAuthToken?: string;
|
||||
dcId?: number;
|
||||
}
|
||||
|
||||
export interface ApiOnProgress {
|
||||
|
||||
@ -64,6 +64,10 @@ export type ApiUpdateAuthorizationState = {
|
||||
qrCode?: { token: string; expires: number };
|
||||
};
|
||||
|
||||
export type ApiUpdateWebAuthTokenFailed = {
|
||||
'@type': 'updateWebAuthTokenFailed';
|
||||
};
|
||||
|
||||
export type ApiUpdateSession = {
|
||||
'@type': 'updateSession';
|
||||
sessionData?: ApiSessionData;
|
||||
@ -549,7 +553,7 @@ export type ApiUpdateTranscribedAudio = {
|
||||
};
|
||||
|
||||
export type ApiUpdate = (
|
||||
ApiUpdateReady | ApiUpdateSession |
|
||||
ApiUpdateReady | ApiUpdateSession | ApiUpdateWebAuthTokenFailed |
|
||||
ApiUpdateAuthorizationState | ApiUpdateAuthorizationError | ApiUpdateConnectionState | ApiUpdateCurrentUser |
|
||||
ApiUpdateChat | ApiUpdateChatInbox | ApiUpdateChatTypingStatus | ApiUpdateChatFullInfo | ApiUpdatePinnedChatIds |
|
||||
ApiUpdateChatMembers | ApiUpdateChatJoin | ApiUpdateChatLeave | ApiUpdateChatPinned | ApiUpdatePinnedMessageIds |
|
||||
|
||||
@ -36,10 +36,10 @@ import useBeforeUnload from '../../hooks/useBeforeUnload';
|
||||
import useOnChange from '../../hooks/useOnChange';
|
||||
import usePreventPinchZoomGesture from '../../hooks/usePreventPinchZoomGesture';
|
||||
import useForceUpdate from '../../hooks/useForceUpdate';
|
||||
import { LOCATION_HASH } from '../../hooks/useHistoryBack';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
import { parseInitialLocationHash, parseLocationHash } from '../../util/routing';
|
||||
|
||||
import StickerSetModal from '../common/StickerSetModal.async';
|
||||
import UnreadCount from '../common/UnreadCounter';
|
||||
@ -193,6 +193,7 @@ const Main: FC<StateProps> = ({
|
||||
closePaymentModal,
|
||||
clearReceipt,
|
||||
checkAppVersion,
|
||||
openChat,
|
||||
} = getActions();
|
||||
|
||||
if (DEBUG && !DEBUG_isLogged) {
|
||||
@ -276,11 +277,25 @@ const Main: FC<StateProps> = ({
|
||||
|
||||
// Parse deep link
|
||||
useEffect(() => {
|
||||
if (lastSyncTime && LOCATION_HASH.startsWith('#?tgaddr=')) {
|
||||
processDeepLink(decodeURIComponent(LOCATION_HASH.substr('#?tgaddr='.length)));
|
||||
const parsedInitialLocationHash = parseInitialLocationHash();
|
||||
if (lastSyncTime && parsedInitialLocationHash?.tgaddr) {
|
||||
processDeepLink(decodeURIComponent(parsedInitialLocationHash.tgaddr));
|
||||
}
|
||||
}, [lastSyncTime]);
|
||||
|
||||
useEffectWithPrevDeps(([prevLastSyncTime]) => {
|
||||
const parsedLocationHash = parseLocationHash();
|
||||
if (!parsedLocationHash) return;
|
||||
|
||||
if (!prevLastSyncTime && lastSyncTime) {
|
||||
openChat({
|
||||
id: parsedLocationHash.chatId,
|
||||
threadId: parsedLocationHash.threadId,
|
||||
type: parsedLocationHash.type,
|
||||
});
|
||||
}
|
||||
}, [lastSyncTime] as const);
|
||||
|
||||
// Prevent refresh by accidentally rotating device when listening to a voice chat
|
||||
useEffect(() => {
|
||||
if (!activeGroupCallId && !isPhoneCallActive) {
|
||||
|
||||
@ -30,6 +30,7 @@ import { forceWebsync } from '../../../util/websync';
|
||||
import { clearGlobalForLockScreen, updatePasscodeSettings } from '../../reducers';
|
||||
import { clearEncryptedSession, encryptSession, forgetPasscode } from '../../../util/passcode';
|
||||
import { serializeGlobal } from '../../cache';
|
||||
import { parseInitialLocationHash } from '../../../util/routing';
|
||||
|
||||
addActionHandler('initApi', async (global, actions) => {
|
||||
if (!IS_TEST) {
|
||||
@ -37,14 +38,18 @@ addActionHandler('initApi', async (global, actions) => {
|
||||
void clearLegacySessions();
|
||||
}
|
||||
|
||||
const initialLocationHash = parseInitialLocationHash();
|
||||
|
||||
void initApi(actions.apiUpdate, {
|
||||
userAgent: navigator.userAgent,
|
||||
platform: PLATFORM_ENV,
|
||||
sessionData: loadStoredSession(),
|
||||
isTest: window.location.search.includes('test'),
|
||||
isTest: window.location.search.includes('test') || initialLocationHash?.tgWebAuthTest === '1',
|
||||
isMovSupported: IS_MOV_SUPPORTED,
|
||||
isWebmSupported: IS_WEBM_SUPPORTED,
|
||||
maxBufferSize: MAX_BUFFER_SIZE,
|
||||
webAuthToken: initialLocationHash?.tgWebAuthToken,
|
||||
dcId: initialLocationHash?.tgWebAuthDcId ? Number(initialLocationHash?.tgWebAuthDcId) : undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import { setLanguage } from '../../../util/langProvider';
|
||||
import { selectNotifySettings } from '../../selectors';
|
||||
import { forceWebsync } from '../../../util/websync';
|
||||
import { getShippingError, shouldClosePaymentModal } from '../../../util/getReadableErrorText';
|
||||
import { clearWebTokenAuth } from '../../../util/routing';
|
||||
|
||||
addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
switch (update['@type']) {
|
||||
@ -33,6 +34,10 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
onUpdateAuthorizationError(update);
|
||||
break;
|
||||
|
||||
case 'updateWebAuthTokenFailed':
|
||||
onUpdateWebAuthTokenFailed();
|
||||
break;
|
||||
|
||||
case 'updateConnectionState':
|
||||
onUpdateConnectionState(update);
|
||||
break;
|
||||
@ -142,6 +147,15 @@ function onUpdateAuthorizationError(update: ApiUpdateAuthorizationError) {
|
||||
});
|
||||
}
|
||||
|
||||
function onUpdateWebAuthTokenFailed() {
|
||||
clearWebTokenAuth();
|
||||
|
||||
setGlobal({
|
||||
...getGlobal(),
|
||||
hasWebAuthTokenFailed: true,
|
||||
});
|
||||
}
|
||||
|
||||
function onUpdateConnectionState(update: ApiUpdateConnectionState) {
|
||||
const { connectionState } = update;
|
||||
const global = getGlobal();
|
||||
|
||||
@ -140,6 +140,7 @@ export type ApiLimitTypeWithModal = Exclude<ApiLimitType, (
|
||||
export type GlobalState = {
|
||||
appConfig?: ApiAppConfig;
|
||||
canInstall?: boolean;
|
||||
hasWebAuthTokenFailed?: boolean;
|
||||
isChatInfoShown: boolean;
|
||||
isStatisticsShown?: boolean;
|
||||
isLeftColumnShown: boolean;
|
||||
|
||||
@ -70,6 +70,7 @@ class TelegramClient {
|
||||
useWSS: false,
|
||||
additionalDcsDisabled: false,
|
||||
testServers: false,
|
||||
dcId: DEFAULT_DC_ID,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -86,6 +87,7 @@ class TelegramClient {
|
||||
const args = { ...TelegramClient.DEFAULT_OPTIONS, ...opts };
|
||||
this.apiId = apiId;
|
||||
this.apiHash = apiHash;
|
||||
this.defaultDcId = args.dcId || DEFAULT_DC_ID;
|
||||
this._useIPV6 = args.useIPV6;
|
||||
// this._entityCache = new Set()
|
||||
if (typeof args.baseLogger === 'string') {
|
||||
@ -221,7 +223,7 @@ class TelegramClient {
|
||||
await this.session.load();
|
||||
|
||||
if (!this.session.serverAddress || (this.session.serverAddress.includes(':') !== this._useIPV6)) {
|
||||
this.session.setDC(DEFAULT_DC_ID, this._useIPV6
|
||||
this.session.setDC(this.defaultDcId, this._useIPV6
|
||||
? DEFAULT_IPV6_IP : DEFAULT_IPV4_IP, this._args.useWSS ? 443 : 80);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import Api from '../tl/api';
|
||||
import TelegramClient from './TelegramClient';
|
||||
import type TelegramClient from './TelegramClient';
|
||||
import utils from '../Utils';
|
||||
import { sleep } from '../Helpers';
|
||||
import { computeCheck as computePasswordSrpCheck } from '../Password';
|
||||
|
||||
export interface UserAuthParams {
|
||||
phoneNumber: string | (() => Promise<string>);
|
||||
webAuthTokenFailed: VoidFunction;
|
||||
phoneCode: (isCodeViaApp?: boolean) => Promise<string>;
|
||||
password: (hint?: string) => Promise<string>;
|
||||
firstAndLastNames: () => Promise<[string, string?]>;
|
||||
@ -14,6 +15,7 @@ export interface UserAuthParams {
|
||||
forceSMS?: boolean;
|
||||
initialMethod?: 'phoneNumber' | 'qrCode';
|
||||
shouldThrowIfUnauthorized?: boolean;
|
||||
webAuthToken?: string;
|
||||
}
|
||||
|
||||
export interface BotAuthParams {
|
||||
@ -37,19 +39,27 @@ export async function authFlow(
|
||||
|
||||
if ('botAuthToken' in authParams) {
|
||||
me = await signInBot(client, apiCredentials, authParams);
|
||||
} else if ('webAuthToken' in authParams && authParams.webAuthToken) {
|
||||
me = await signInUserWithWebToken(client, apiCredentials, authParams);
|
||||
} else {
|
||||
const { initialMethod = DEFAULT_INITIAL_METHOD } = authParams;
|
||||
|
||||
if (initialMethod === 'phoneNumber') {
|
||||
me = await signInUser(client, apiCredentials, authParams);
|
||||
} else {
|
||||
me = await signInUserWithQrCode(client, apiCredentials, authParams);
|
||||
}
|
||||
me = await signInUserWithPreferredMethod(client, apiCredentials, authParams);
|
||||
}
|
||||
|
||||
client._log.info('Signed in successfully as', utils.getDisplayName(me));
|
||||
}
|
||||
|
||||
export async function signInUserWithPreferredMethod(
|
||||
client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
|
||||
): Promise<Api.TypeUser> {
|
||||
const { initialMethod = DEFAULT_INITIAL_METHOD } = authParams;
|
||||
|
||||
if (initialMethod === 'phoneNumber') {
|
||||
return signInUser(client, apiCredentials, authParams);
|
||||
} else {
|
||||
return signInUserWithQrCode(client, apiCredentials, authParams);
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkAuthorization(client: TelegramClient, shouldThrow = false) {
|
||||
try {
|
||||
await client.invoke(new Api.updates.GetState());
|
||||
@ -60,6 +70,36 @@ export async function checkAuthorization(client: TelegramClient, shouldThrow = f
|
||||
}
|
||||
}
|
||||
|
||||
async function signInUserWithWebToken(
|
||||
client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
|
||||
): Promise<Api.TypeUser> {
|
||||
try {
|
||||
const { apiId, apiHash } = apiCredentials;
|
||||
const sendResult = await client.invoke(new Api.auth.ImportWebTokenAuthorization({
|
||||
webAuthToken: authParams.webAuthToken,
|
||||
apiId,
|
||||
apiHash,
|
||||
}));
|
||||
|
||||
if (sendResult instanceof Api.auth.Authorization) {
|
||||
return sendResult.user;
|
||||
} else {
|
||||
throw new Error('SIGN_UP_REQUIRED');
|
||||
}
|
||||
} catch (err: any) {
|
||||
authParams.webAuthTokenFailed();
|
||||
client._log.error('Failed to login with web token', err);
|
||||
if (err.message === 'SESSION_PASSWORD_NEEDED') {
|
||||
return signInWithPassword(client, apiCredentials, authParams);
|
||||
} else {
|
||||
return signInUserWithPreferredMethod(client, apiCredentials, {
|
||||
...authParams,
|
||||
webAuthToken: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function signInUser(
|
||||
client: TelegramClient, apiCredentials: ApiCredentials, authParams: UserAuthParams,
|
||||
): Promise<Api.TypeUser> {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const api = require('./api');
|
||||
|
||||
const LAYER = 146;
|
||||
const LAYER = 147;
|
||||
const tlobjects = {};
|
||||
|
||||
for (const tl of Object.values(api)) {
|
||||
|
||||
25
src/lib/gramjs/tl/api.d.ts
vendored
25
src/lib/gramjs/tl/api.d.ts
vendored
@ -293,6 +293,7 @@ namespace Api {
|
||||
export type TypePremiumSubscriptionOption = PremiumSubscriptionOption;
|
||||
export type TypeSendAsPeer = SendAsPeer;
|
||||
export type TypeMessageExtendedMedia = MessageExtendedMediaPreview | MessageExtendedMedia;
|
||||
export type TypeStickerKeyword = StickerKeyword;
|
||||
export type TypeResPQ = ResPQ;
|
||||
export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc;
|
||||
export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk;
|
||||
@ -4772,10 +4773,12 @@ namespace Api {
|
||||
export class StickerSetFullCovered extends VirtualClass<{
|
||||
set: Api.TypeStickerSet;
|
||||
packs: Api.TypeStickerPack[];
|
||||
keywords: Api.TypeStickerKeyword[];
|
||||
documents: Api.TypeDocument[];
|
||||
}> {
|
||||
set: Api.TypeStickerSet;
|
||||
packs: Api.TypeStickerPack[];
|
||||
keywords: Api.TypeStickerKeyword[];
|
||||
documents: Api.TypeDocument[];
|
||||
};
|
||||
export class MaskCoords extends VirtualClass<{
|
||||
@ -5846,6 +5849,7 @@ namespace Api {
|
||||
groupCall?: true;
|
||||
invites?: true;
|
||||
send?: true;
|
||||
forums?: true;
|
||||
} | void> {
|
||||
// flags: undefined;
|
||||
join?: true;
|
||||
@ -5865,6 +5869,7 @@ namespace Api {
|
||||
groupCall?: true;
|
||||
invites?: true;
|
||||
send?: true;
|
||||
forums?: true;
|
||||
};
|
||||
export class PopularContact extends VirtualClass<{
|
||||
clientId: long;
|
||||
@ -7587,6 +7592,13 @@ namespace Api {
|
||||
}> {
|
||||
media: Api.TypeMessageMedia;
|
||||
};
|
||||
export class StickerKeyword extends VirtualClass<{
|
||||
documentId: long;
|
||||
keyword: string[];
|
||||
}> {
|
||||
documentId: long;
|
||||
keyword: string[];
|
||||
};
|
||||
export class ResPQ extends VirtualClass<{
|
||||
nonce: int128;
|
||||
serverNonce: int128;
|
||||
@ -8321,10 +8333,12 @@ namespace Api {
|
||||
export class StickerSet extends VirtualClass<{
|
||||
set: Api.TypeStickerSet;
|
||||
packs: Api.TypeStickerPack[];
|
||||
keywords: Api.TypeStickerKeyword[];
|
||||
documents: Api.TypeDocument[];
|
||||
}> {
|
||||
set: Api.TypeStickerSet;
|
||||
packs: Api.TypeStickerPack[];
|
||||
keywords: Api.TypeStickerKeyword[];
|
||||
documents: Api.TypeDocument[];
|
||||
};
|
||||
export class StickerSetNotModified extends VirtualClass<void> {};
|
||||
@ -9840,6 +9854,15 @@ namespace Api {
|
||||
}>, Bool> {
|
||||
code: string;
|
||||
};
|
||||
export class ImportWebTokenAuthorization extends Request<Partial<{
|
||||
apiId: int;
|
||||
apiHash: string;
|
||||
webAuthToken: string;
|
||||
}>, auth.TypeAuthorization> {
|
||||
apiId: int;
|
||||
apiHash: string;
|
||||
webAuthToken: string;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace account {
|
||||
@ -13355,7 +13378,7 @@ namespace Api {
|
||||
}
|
||||
|
||||
export type AnyRequest = InvokeAfterMsg | InvokeAfterMsgs | InitConnection | InvokeWithLayer | InvokeWithoutUpdates | InvokeWithMessagesRange | InvokeWithTakeout | ReqPq | ReqPqMulti | ReqPqMultiNew | ReqDHParams | SetClientDHParams | DestroyAuthKey | RpcDropAnswer | GetFutureSalts | Ping | PingDelayDisconnect | DestroySession
|
||||
| auth.SendCode | auth.SignUp | auth.SignIn | auth.LogOut | auth.ResetAuthorizations | auth.ExportAuthorization | auth.ImportAuthorization | auth.BindTempAuthKey | auth.ImportBotAuthorization | auth.CheckPassword | auth.RequestPasswordRecovery | auth.RecoverPassword | auth.ResendCode | auth.CancelCode | auth.DropTempAuthKeys | auth.ExportLoginToken | auth.ImportLoginToken | auth.AcceptLoginToken | auth.CheckRecoveryPassword
|
||||
| auth.SendCode | auth.SignUp | auth.SignIn | auth.LogOut | auth.ResetAuthorizations | auth.ExportAuthorization | auth.ImportAuthorization | auth.BindTempAuthKey | auth.ImportBotAuthorization | auth.CheckPassword | auth.RequestPasswordRecovery | auth.RecoverPassword | auth.ResendCode | auth.CancelCode | auth.DropTempAuthKeys | auth.ExportLoginToken | auth.ImportLoginToken | auth.AcceptLoginToken | auth.CheckRecoveryPassword | auth.ImportWebTokenAuthorization
|
||||
| account.RegisterDevice | account.UnregisterDevice | account.UpdateNotifySettings | account.GetNotifySettings | account.ResetNotifySettings | account.UpdateProfile | account.UpdateStatus | account.GetWallPapers | account.ReportPeer | account.CheckUsername | account.UpdateUsername | account.GetPrivacy | account.SetPrivacy | account.DeleteAccount | account.GetAccountTTL | account.SetAccountTTL | account.SendChangePhoneCode | account.ChangePhone | account.UpdateDeviceLocked | account.GetAuthorizations | account.ResetAuthorization | account.GetPassword | account.GetPasswordSettings | account.UpdatePasswordSettings | account.SendConfirmPhoneCode | account.ConfirmPhone | account.GetTmpPassword | account.GetWebAuthorizations | account.ResetWebAuthorization | account.ResetWebAuthorizations | account.GetAllSecureValues | account.GetSecureValue | account.SaveSecureValue | account.DeleteSecureValue | account.GetAuthorizationForm | account.AcceptAuthorization | account.SendVerifyPhoneCode | account.VerifyPhone | account.SendVerifyEmailCode | account.VerifyEmail | account.InitTakeoutSession | account.FinishTakeoutSession | account.ConfirmPasswordEmail | account.ResendPasswordEmail | account.CancelPasswordEmail | account.GetContactSignUpNotification | account.SetContactSignUpNotification | account.GetNotifyExceptions | account.GetWallPaper | account.UploadWallPaper | account.SaveWallPaper | account.InstallWallPaper | account.ResetWallPapers | account.GetAutoDownloadSettings | account.SaveAutoDownloadSettings | account.UploadTheme | account.CreateTheme | account.UpdateTheme | account.SaveTheme | account.InstallTheme | account.GetTheme | account.GetThemes | account.SetContentSettings | account.GetContentSettings | account.GetMultiWallPapers | account.GetGlobalPrivacySettings | account.SetGlobalPrivacySettings | account.ReportProfilePhoto | account.ResetPassword | account.DeclinePasswordReset | account.GetChatThemes | account.SetAuthorizationTTL | account.ChangeAuthorizationSettings | account.GetSavedRingtones | account.SaveRingtone | account.UploadRingtone | account.UpdateEmojiStatus | account.GetDefaultEmojiStatuses | account.GetRecentEmojiStatuses | account.ClearRecentEmojiStatuses
|
||||
| users.GetUsers | users.GetFullUser | users.SetSecureValueErrors
|
||||
| contacts.GetContactIDs | contacts.GetStatuses | contacts.GetContacts | contacts.ImportContacts | contacts.DeleteContacts | contacts.DeleteByPhones | contacts.Block | contacts.Unblock | contacts.GetBlocked | contacts.Search | contacts.ResolveUsername | contacts.GetTopPeers | contacts.ResetTopPeerRating | contacts.ResetSaved | contacts.GetSaved | contacts.ToggleTopPeers | contacts.AddContact | contacts.AcceptContact | contacts.GetLocated | contacts.BlockFromReplies | contacts.ResolvePhone
|
||||
|
||||
@ -460,7 +460,7 @@ inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
|
||||
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
|
||||
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
|
||||
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
botInfo#8f300b57 flags:# user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector<BotCommand> menu_button:flags.3?BotMenuButton = BotInfo;
|
||||
@ -598,7 +598,7 @@ messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallRes
|
||||
messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult;
|
||||
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
|
||||
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#1aed5ee5 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = StickerSetCovered;
|
||||
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||
inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
|
||||
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
|
||||
@ -741,7 +741,7 @@ channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLog
|
||||
channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction;
|
||||
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
|
||||
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true = ChannelAdminLogEventsFilter;
|
||||
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter;
|
||||
popularContact#5ce14175 client_id:long importers:int = PopularContact;
|
||||
messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
|
||||
messages.favedStickers#2cb51097 hash:long packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;
|
||||
@ -1045,6 +1045,7 @@ premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upg
|
||||
sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;
|
||||
messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
|
||||
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;
|
||||
stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword;
|
||||
---functions---
|
||||
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
|
||||
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
@ -1063,6 +1064,7 @@ auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
|
||||
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
|
||||
auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector<long> = auth.LoginToken;
|
||||
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
|
||||
auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization;
|
||||
account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<long> = Bool;
|
||||
account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector<long> = Bool;
|
||||
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
"auth.resetAuthorizations",
|
||||
"auth.exportAuthorization",
|
||||
"auth.importAuthorization",
|
||||
"auth.importWebTokenAuthorization",
|
||||
"auth.bindTempAuthKey",
|
||||
"auth.checkPassword",
|
||||
"auth.requestPasswordRecovery",
|
||||
|
||||
@ -561,7 +561,7 @@ inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
|
||||
|
||||
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
|
||||
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
@ -740,7 +740,7 @@ messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered>
|
||||
|
||||
stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
|
||||
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#1aed5ee5 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = StickerSetCovered;
|
||||
stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = StickerSetCovered;
|
||||
|
||||
maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||
|
||||
@ -927,7 +927,7 @@ channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminL
|
||||
|
||||
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
|
||||
|
||||
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true = ChannelAdminLogEventsFilter;
|
||||
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter;
|
||||
|
||||
popularContact#5ce14175 client_id:long importers:int = PopularContact;
|
||||
|
||||
@ -1418,6 +1418,8 @@ sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer
|
||||
messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
|
||||
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;
|
||||
|
||||
stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1447,6 +1449,7 @@ auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector<long
|
||||
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
|
||||
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
|
||||
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
|
||||
auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization;
|
||||
|
||||
account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<long> = Bool;
|
||||
account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector<long> = Bool;
|
||||
@ -1894,4 +1897,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
|
||||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 146
|
||||
// LAYER 147
|
||||
|
||||
@ -2,6 +2,10 @@ import type { MessageListType } from '../global/types';
|
||||
import { MAIN_THREAD_ID } from '../api/types';
|
||||
import { LOCATION_HASH } from '../hooks/useHistoryBack';
|
||||
|
||||
let parsedInitialLocationHash: Record<string, string> | undefined;
|
||||
let messageHash: string | undefined;
|
||||
let isAlreadyParsed = false;
|
||||
|
||||
export const createMessageHash = (chatId: string, type: string, threadId: number): string => (
|
||||
chatId.toString()
|
||||
+ (type !== 'thread' ? `_${type}`
|
||||
@ -9,9 +13,11 @@ export const createMessageHash = (chatId: string, type: string, threadId: number
|
||||
);
|
||||
|
||||
export function parseLocationHash() {
|
||||
if (!LOCATION_HASH) return undefined;
|
||||
parseInitialLocationHash();
|
||||
|
||||
const [chatId, typeOrThreadId] = LOCATION_HASH.replace(/^#/, '').split('_');
|
||||
if (!messageHash) return undefined;
|
||||
|
||||
const [chatId, typeOrThreadId] = messageHash.split('_');
|
||||
if (!chatId?.match(/^-?\d+$/)) return undefined;
|
||||
|
||||
const isType = ['thread', 'pinned', 'scheduled'].includes(typeOrThreadId);
|
||||
@ -22,3 +28,37 @@ export function parseLocationHash() {
|
||||
threadId: Boolean(typeOrThreadId) && !isType ? Number(typeOrThreadId) : MAIN_THREAD_ID,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseInitialLocationHash() {
|
||||
if (parsedInitialLocationHash) return parsedInitialLocationHash;
|
||||
|
||||
if (isAlreadyParsed) return undefined;
|
||||
|
||||
if (!LOCATION_HASH) return undefined;
|
||||
|
||||
let parsedHash = LOCATION_HASH ? LOCATION_HASH.replace(/^#/, '') : undefined;
|
||||
if (parsedHash?.includes('?')) {
|
||||
[messageHash, parsedHash] = parsedHash.split('?');
|
||||
window.location.hash = messageHash;
|
||||
} else if (parsedHash?.includes('=')) {
|
||||
window.location.hash = '';
|
||||
}
|
||||
|
||||
parsedInitialLocationHash = parsedHash?.includes('=') ? parsedHash?.split('&').reduce((acc, cur) => {
|
||||
const [key, value] = cur.split('=');
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {} as Record<string, string>) : undefined;
|
||||
isAlreadyParsed = true;
|
||||
if (!parsedInitialLocationHash) {
|
||||
messageHash = parsedHash;
|
||||
}
|
||||
|
||||
return parsedInitialLocationHash;
|
||||
}
|
||||
|
||||
export function clearWebTokenAuth() {
|
||||
if (!parsedInitialLocationHash) return;
|
||||
|
||||
delete parsedInitialLocationHash.tgWebAuthToken;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user