changed api
This commit is contained in:
@@ -19,5 +19,12 @@
|
|||||||
"changeOrigin": true,
|
"changeOrigin": true,
|
||||||
"pathRewrite": { "^/proxy/api-vitanova": "" },
|
"pathRewrite": { "^/proxy/api-vitanova": "" },
|
||||||
"logLevel": "debug"
|
"logLevel": "debug"
|
||||||
|
},
|
||||||
|
"/proxy/users-vitanova": {
|
||||||
|
"target": "https://users.vitanova.network:456",
|
||||||
|
"secure": true,
|
||||||
|
"changeOrigin": true,
|
||||||
|
"pathRewrite": { "^/proxy/users-vitanova": "" },
|
||||||
|
"logLevel": "debug"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ export const FASTCHECK_API = isDevMode()
|
|||||||
? '/proxy/fastcheck-store/api'
|
? '/proxy/fastcheck-store/api'
|
||||||
: 'https://fastcheck.store/api';
|
: 'https://fastcheck.store/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL for Telegram/websession authorization.
|
||||||
|
* Auth routes: POST /users/sessions, GET/DELETE /users/sessions/:webSessionID.
|
||||||
|
*/
|
||||||
|
export const USERS_VITANOVA_API = isDevMode()
|
||||||
|
? '/proxy/users-vitanova'
|
||||||
|
: 'https://users.vitanova.network:456';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL for the QR/SBP backend (qr.vitanova.network).
|
* Base URL for the QR/SBP backend (qr.vitanova.network).
|
||||||
* Used for the /api/settings endpoint that may return active check data on load.
|
* Used for the /api/settings endpoint that may return active check data on load.
|
||||||
|
|||||||
@@ -30,6 +30,10 @@
|
|||||||
{{ 'auth.telegram_btn' | translate }}
|
{{ 'auth.telegram_btn' | translate }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<a class="telegram-link" [href]="telegramLink()" target="_blank" rel="noopener">
|
||||||
|
{{ telegramLink() }}
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="qr-section">
|
<div class="qr-section">
|
||||||
<p class="qr-hint">{{ 'auth.qr_hint' | translate }}</p>
|
<p class="qr-hint">{{ 'auth.qr_hint' | translate }}</p>
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,20 @@ h2 {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.telegram-link {
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: var(--telegram-hover);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.telegram-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.qr-section {
|
.qr-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component, computed, effect, inject, input, output, signal } from '@angular/core';
|
import { Component, computed, effect, inject, input, output, signal } from '@angular/core';
|
||||||
import { FASTCHECK_API } from '../api';
|
import { USERS_VITANOVA_API } from '../api';
|
||||||
import { TranslatePipe } from '../translate/translate.pipe';
|
import { TranslatePipe } from '../translate/translate.pipe';
|
||||||
|
|
||||||
interface WebSessionResponse {
|
interface WebSessionResponse {
|
||||||
sessionId: string;
|
sessionId?: string;
|
||||||
userId: string;
|
webSessionID?: string;
|
||||||
expires: string;
|
webSessionId?: string;
|
||||||
userSessionId: string;
|
userId?: string;
|
||||||
Status: boolean;
|
userID?: string;
|
||||||
|
telegramID?: string;
|
||||||
|
expires?: string;
|
||||||
|
userSessionId?: string;
|
||||||
|
userSessionID?: string;
|
||||||
|
Status?: boolean;
|
||||||
|
status?: boolean | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AuthDialogMode = 'payment' | 'login' | 'new';
|
export type AuthDialogMode = 'payment' | 'login' | 'new';
|
||||||
@@ -31,7 +37,6 @@ export class AuthDialogComponent {
|
|||||||
private readonly http = inject(HttpClient);
|
private readonly http = inject(HttpClient);
|
||||||
private readonly telegramBot = 'myAMLKYCBOT';
|
private readonly telegramBot = 'myAMLKYCBOT';
|
||||||
private readonly sessionStorageKey = 'fc_session';
|
private readonly sessionStorageKey = 'fc_session';
|
||||||
private readonly maxPollAttempts = 100;
|
|
||||||
|
|
||||||
open = input(false);
|
open = input(false);
|
||||||
mode = input<AuthDialogMode>('login');
|
mode = input<AuthDialogMode>('login');
|
||||||
@@ -61,7 +66,6 @@ export class AuthDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private pollHandle: ReturnType<typeof setInterval> | null = null;
|
private pollHandle: ReturnType<typeof setInterval> | null = null;
|
||||||
private pollAttempts = 0;
|
|
||||||
private wasOpen = false;
|
private wasOpen = false;
|
||||||
private authenticated = false;
|
private authenticated = false;
|
||||||
|
|
||||||
@@ -106,7 +110,6 @@ export class AuthDialogComponent {
|
|||||||
private startAuthFlow(): void {
|
private startAuthFlow(): void {
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
this.authenticated = false;
|
this.authenticated = false;
|
||||||
this.pollAttempts = 0;
|
|
||||||
this.messageKey.set('');
|
this.messageKey.set('');
|
||||||
this.webSessionId.set('');
|
this.webSessionId.set('');
|
||||||
this.state.set('checking');
|
this.state.set('checking');
|
||||||
@@ -121,9 +124,9 @@ export class AuthDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private checkExistingSession(sessionId: string): void {
|
private checkExistingSession(sessionId: string): void {
|
||||||
this.http.get<WebSessionResponse>(`${FASTCHECK_API}/websession/${sessionId}`).subscribe({
|
this.http.get<WebSessionResponse>(`${USERS_VITANOVA_API}/users/sessions/${sessionId}`).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
if (response?.Status) {
|
if (this.isAuthorized(response)) {
|
||||||
this.webSessionId.set(sessionId);
|
this.webSessionId.set(sessionId);
|
||||||
this.handleAuthorized(response, sessionId);
|
this.handleAuthorized(response, sessionId);
|
||||||
return;
|
return;
|
||||||
@@ -141,26 +144,30 @@ export class AuthDialogComponent {
|
|||||||
|
|
||||||
private createSession(): void {
|
private createSession(): void {
|
||||||
this.state.set('loading');
|
this.state.set('loading');
|
||||||
this.http.get<WebSessionResponse>(`${FASTCHECK_API}/websession`).subscribe({
|
const sessionId = this.createGuid();
|
||||||
|
this.webSessionId.set(sessionId);
|
||||||
|
|
||||||
|
this.http.post<WebSessionResponse>(`${USERS_VITANOVA_API}/users/sessions`, {
|
||||||
|
webSessionID: sessionId,
|
||||||
|
sessionId
|
||||||
|
}).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
const sessionId = response?.sessionId ?? '';
|
const responseSessionId = this.getSessionId(response) || sessionId;
|
||||||
if (!sessionId) {
|
if (!responseSessionId) {
|
||||||
this.messageKey.set('auth.session_failed');
|
this.messageKey.set('auth.session_failed');
|
||||||
this.state.set('error');
|
this.state.set('error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.webSessionId.set(sessionId);
|
this.webSessionId.set(responseSessionId);
|
||||||
|
|
||||||
if (this.isMobile) {
|
if (this.isAuthorized(response)) {
|
||||||
this.state.set('checking');
|
this.handleAuthorized(response, responseSessionId);
|
||||||
window.location.href = this.telegramLink();
|
|
||||||
this.startPolling(sessionId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state.set('ready');
|
this.state.set('ready');
|
||||||
this.startPolling(sessionId);
|
this.startPolling(responseSessionId);
|
||||||
},
|
},
|
||||||
error: () => {
|
error: () => {
|
||||||
this.messageKey.set('auth.session_failed');
|
this.messageKey.set('auth.session_failed');
|
||||||
@@ -171,19 +178,10 @@ export class AuthDialogComponent {
|
|||||||
|
|
||||||
private startPolling(sessionId: string): void {
|
private startPolling(sessionId: string): void {
|
||||||
this.stopPolling();
|
this.stopPolling();
|
||||||
this.pollAttempts = 0;
|
|
||||||
this.pollHandle = setInterval(() => {
|
this.pollHandle = setInterval(() => {
|
||||||
this.pollAttempts += 1;
|
this.http.get<WebSessionResponse>(`${USERS_VITANOVA_API}/users/sessions/${sessionId}`).subscribe({
|
||||||
if (this.pollAttempts >= this.maxPollAttempts) {
|
|
||||||
this.stopPolling();
|
|
||||||
this.messageKey.set('auth.expired');
|
|
||||||
this.state.set('expired');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.http.get<WebSessionResponse>(`${FASTCHECK_API}/websession/${sessionId}`).subscribe({
|
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
if (!response?.Status) return;
|
if (!this.isAuthorized(response)) return;
|
||||||
this.handleAuthorized(response, sessionId);
|
this.handleAuthorized(response, sessionId);
|
||||||
},
|
},
|
||||||
error: () => undefined
|
error: () => undefined
|
||||||
@@ -200,8 +198,8 @@ export class AuthDialogComponent {
|
|||||||
this.state.set('checking');
|
this.state.set('checking');
|
||||||
this.authorized.emit({
|
this.authorized.emit({
|
||||||
sessionId,
|
sessionId,
|
||||||
userId: response.userId ?? '',
|
userId: response.userId ?? response.userID ?? response.telegramID ?? '',
|
||||||
userSessionId: response.userSessionId ?? ''
|
userSessionId: response.userSessionId ?? response.userSessionID ?? ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +210,6 @@ export class AuthDialogComponent {
|
|||||||
this.webSessionId.set('');
|
this.webSessionId.set('');
|
||||||
this.state.set('loading');
|
this.state.set('loading');
|
||||||
this.authenticated = false;
|
this.authenticated = false;
|
||||||
this.pollAttempts = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private cleanupSession(persistSession: boolean): void {
|
private cleanupSession(persistSession: boolean): void {
|
||||||
@@ -232,14 +229,33 @@ export class AuthDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.http
|
this.http
|
||||||
.request('DELETE', `${FASTCHECK_API}/websession/${sessionId}`, {
|
.delete(`${USERS_VITANOVA_API}/users/sessions/${sessionId}`)
|
||||||
body: { sessionId }
|
|
||||||
})
|
|
||||||
.subscribe({ error: () => undefined });
|
.subscribe({ error: () => undefined });
|
||||||
|
|
||||||
localStorage.removeItem(this.sessionStorageKey);
|
localStorage.removeItem(this.sessionStorageKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSessionId(response: WebSessionResponse | null | undefined): string {
|
||||||
|
return response?.webSessionID ?? response?.webSessionId ?? response?.sessionId ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAuthorized(response: WebSessionResponse | null | undefined): boolean {
|
||||||
|
const status = response?.Status ?? response?.status;
|
||||||
|
return status === true || String(status).toLowerCase() === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
private createGuid(): string {
|
||||||
|
if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
|
||||||
|
return crypto.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
||||||
|
const randomValue = Math.floor(Math.random() * 16);
|
||||||
|
const value = char === 'x' ? randomValue : (randomValue & 0x3) | 0x8;
|
||||||
|
return value.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private stopPolling(): void {
|
private stopPolling(): void {
|
||||||
if (this.pollHandle === null) return;
|
if (this.pollHandle === null) return;
|
||||||
clearInterval(this.pollHandle);
|
clearInterval(this.pollHandle);
|
||||||
|
|||||||
Reference in New Issue
Block a user