138 lines
6.7 KiB
JavaScript
138 lines
6.7 KiB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
};
|
|
import { Injectable, inject } from '@angular/core';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { of, catchError, map } from 'rxjs';
|
|
import { AUTH_API_URL, TELEGRAM_BOT_USERNAME } from '../config';
|
|
import { generateGuid } from '../util/guid.util';
|
|
const SESSION_MAX_AGE_SECONDS = 60 * 60;
|
|
const DEFAULT_TELEGRAM_BOT_USERNAME = 'DexarSupport_bot';
|
|
/**
|
|
* The one Telegram QR/session API (`{authApiUrl}/users/sessions`). Customer
|
|
* login (AuthService) and admin login (AdminAuthService) both call this same
|
|
* service against this same endpoint - there is no separate admin backend.
|
|
* This class only does the HTTP call + response normalization; it holds no
|
|
* session state and writes no cookies, so each caller manages its own
|
|
* storage/signals independently on top of it.
|
|
*/
|
|
let TelegramSessionApiService = class TelegramSessionApiService {
|
|
constructor() {
|
|
this.http = inject(HttpClient);
|
|
this.authApiUrl = inject(AUTH_API_URL);
|
|
this.telegramBotUsername = inject(TELEGRAM_BOT_USERNAME, { optional: true });
|
|
}
|
|
createSession() {
|
|
const webSessionID = generateGuid();
|
|
return this.http.post(`${this.authApiUrl}/users/sessions`, { webSessionID }, { headers: { WebSessionID: webSessionID } }).pipe(map(response => {
|
|
const responseWebSessionID = this.extractSessionId(response, webSessionID);
|
|
return {
|
|
webSessionID: responseWebSessionID,
|
|
url: this.getBotLoginUrl(responseWebSessionID),
|
|
};
|
|
}));
|
|
}
|
|
checkSessionOnce(webSessionID) {
|
|
if (!webSessionID) {
|
|
return of(null);
|
|
}
|
|
return this.http.get(`${this.authApiUrl}/users/sessions/${encodeURIComponent(webSessionID)}`).pipe(map(response => this.normalizeWebSession(response, webSessionID)), catchError(() => of(null)));
|
|
}
|
|
logout(webSessionID) {
|
|
return this.http.delete(`${this.authApiUrl}/users/sessions/${encodeURIComponent(webSessionID)}`, {
|
|
headers: { WebSessionID: webSessionID }
|
|
}).pipe(catchError(() => of(null)));
|
|
}
|
|
getBotLoginUrl(webSessionID) {
|
|
return `https://t.me/${this.getBotUsername()}?start=${encodeURIComponent(webSessionID)}`;
|
|
}
|
|
getBotAppLoginUrl(webSessionID) {
|
|
return `tg://resolve?domain=${encodeURIComponent(this.getBotUsername())}&start=${encodeURIComponent(webSessionID)}`;
|
|
}
|
|
getBotUsername() {
|
|
return this.telegramBotUsername || DEFAULT_TELEGRAM_BOT_USERNAME;
|
|
}
|
|
normalizeWebSession(response, fallbackSessionId) {
|
|
if (!response) {
|
|
return null;
|
|
}
|
|
const user = this.asRecord(this.readFirst(response, ['user', 'User', 'telegramUser', 'TelegramUser'])) ?? response;
|
|
const status = this.readFirst(response, [
|
|
'status', 'Status', 'active', 'Active', 'loggedIn', 'LoggedIn',
|
|
'isLoggedIn', 'IsLoggedIn', 'authenticated', 'Authenticated'
|
|
]);
|
|
const active = this.isActiveStatus(status);
|
|
const sessionId = this.extractSessionId(response, fallbackSessionId);
|
|
const username = this.readString(this.readFirst(user, ['username', 'Username']))
|
|
?? this.readString(this.readFirst(response, ['username', 'Username']));
|
|
const firstName = this.readString(this.readFirst(user, ['firstName', 'first_name', 'FirstName', 'First_name']));
|
|
const lastName = this.readString(this.readFirst(user, ['lastName', 'last_name', 'LastName', 'Last_name']));
|
|
const fullName = [firstName, lastName].filter(Boolean).join(' ');
|
|
const explicitDisplayName = this.readString(this.readFirst(response, ['displayName', 'DisplayName', 'name', 'Name']))
|
|
?? this.readString(this.readFirst(user, ['displayName', 'DisplayName', 'name', 'Name']));
|
|
const displayName = explicitDisplayName ?? username ?? (fullName || 'Telegram User');
|
|
const telegramUserId = this.readNumber(this.readFirst(user, ['userId', 'telegramUserId', 'telegramUserID', 'TelegramUserID', 'id', 'ID']))
|
|
?? this.readNumber(this.readFirst(response, ['userId', 'telegramUserId', 'telegramUserID', 'TelegramUserID', 'userID', 'UserID', 'UserId']))
|
|
?? null;
|
|
const expiresAt = this.readString(this.readFirst(response, ['expiresAt', 'ExpiresAt', 'expires', 'Expires']))
|
|
?? new Date(Date.now() + SESSION_MAX_AGE_SECONDS * 1000).toISOString();
|
|
return { sessionId, userId: telegramUserId, username, displayName, active, expires: expiresAt };
|
|
}
|
|
extractSessionId(response, fallbackSessionId) {
|
|
if (!response) {
|
|
return fallbackSessionId;
|
|
}
|
|
return this.readString(this.readFirst(response, [
|
|
'webSessionID', 'WebSessionID', 'webSessionId', 'sessionID', 'SessionID', 'sessionId', 'id', 'ID'
|
|
])) ?? fallbackSessionId;
|
|
}
|
|
readFirst(source, keys) {
|
|
for (const key of keys) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
return source[key];
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
readString(value) {
|
|
if (typeof value === 'string' && value.trim()) {
|
|
return value;
|
|
}
|
|
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
return value.toString();
|
|
}
|
|
return null;
|
|
}
|
|
readNumber(value) {
|
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
return value;
|
|
}
|
|
if (typeof value === 'string') {
|
|
const parsed = Number(value);
|
|
return Number.isFinite(parsed) ? parsed : null;
|
|
}
|
|
return null;
|
|
}
|
|
asRecord(value) {
|
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
? value
|
|
: null;
|
|
}
|
|
isActiveStatus(status) {
|
|
if (status === true || status === 1) {
|
|
return true;
|
|
}
|
|
if (typeof status !== 'string') {
|
|
return false;
|
|
}
|
|
return ['true', '1', 'active', 'authenticated', 'confirmed', 'success', 'logged_in'].includes(status.toLowerCase());
|
|
}
|
|
};
|
|
TelegramSessionApiService = __decorate([
|
|
Injectable({ providedIn: 'root' })
|
|
], TelegramSessionApiService);
|
|
export { TelegramSessionApiService };
|