add oauth app connected
This commit is contained in:
@@ -127,6 +127,30 @@ export interface OAuthScope {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface OAuthConsentScopeInfo {
|
||||
slug: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface OAuthConsentCheckResponse {
|
||||
granted: boolean;
|
||||
client?: {
|
||||
clientId: string;
|
||||
name: string;
|
||||
};
|
||||
requestedScopes?: OAuthConsentScopeInfo[];
|
||||
}
|
||||
|
||||
export interface OAuthUserConsent {
|
||||
id: string;
|
||||
clientId: string;
|
||||
clientName: string;
|
||||
scopes: OAuthConsentScopeInfo[];
|
||||
grantedAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface OAuthClient {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -411,15 +435,35 @@ export async function fetchAuthSession(token?: string | null): Promise<AuthSessi
|
||||
}
|
||||
|
||||
export async function approveOAuthAuthorization(params: URLSearchParams, token: string) {
|
||||
const body = {
|
||||
client_id: params.get('client_id') ?? params.get('clientId') ?? undefined,
|
||||
redirect_uri: params.get('redirect_uri') ?? params.get('redirectUri') ?? undefined,
|
||||
scope: params.get('scope') ?? 'openid profile',
|
||||
state: params.get('state') ?? undefined,
|
||||
nonce: params.get('nonce') ?? undefined
|
||||
};
|
||||
return apiFetch<{ redirectUrl?: string }>('/oauth/consent/approve', {
|
||||
method: 'POST',
|
||||
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
}, token);
|
||||
}
|
||||
|
||||
export async function checkOAuthConsent(params: URLSearchParams, token: string) {
|
||||
const query = new URLSearchParams();
|
||||
params.forEach((value, key) => {
|
||||
if (key !== 'userId') query.set(key, value);
|
||||
});
|
||||
return apiFetch<{ redirectUrl?: string }>(
|
||||
`/oauth/authorize?${query.toString()}`,
|
||||
{ headers: { Accept: 'application/json' } },
|
||||
token
|
||||
);
|
||||
const clientId = params.get('client_id') ?? params.get('clientId');
|
||||
const scope = params.get('scope') ?? 'openid profile';
|
||||
if (clientId) query.set('client_id', clientId);
|
||||
query.set('scope', scope);
|
||||
return apiFetch<OAuthConsentCheckResponse>(`/oauth/consent/check?${query.toString()}`, {}, token);
|
||||
}
|
||||
|
||||
export async function fetchUserOAuthConsents(userId: string, token: string) {
|
||||
return apiFetch<{ consents?: OAuthUserConsent[] }>(`/oauth/consents/users/${userId}`, {}, token);
|
||||
}
|
||||
|
||||
export async function revokeOAuthConsent(userId: string, consentId: string, token: string) {
|
||||
return apiFetch(`/oauth/consents/users/${userId}/${consentId}`, { method: 'DELETE' }, token);
|
||||
}
|
||||
|
||||
export async function refreshAuthSession(): Promise<RefreshSessionResponse> {
|
||||
|
||||
@@ -36,6 +36,16 @@ export function getMessageCopyText(message: ChatMessage, visibleText?: string) {
|
||||
return '';
|
||||
}
|
||||
|
||||
function looksLikeEncryptedPayload(content?: string | null) {
|
||||
if (!content?.trim().startsWith('{')) return false;
|
||||
try {
|
||||
const parsed = JSON.parse(content) as { v?: unknown; ciphertext?: unknown; kind?: unknown };
|
||||
return typeof parsed === 'object' && parsed !== null && ('v' in parsed || 'ciphertext' in parsed || 'kind' in parsed);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getMessagePreviewText(message: ChatMessage, visibleText?: string) {
|
||||
if (message.type === 'SYSTEM') {
|
||||
return resolveNativeEmojiContent(message.content?.trim() ?? 'Системное сообщение');
|
||||
@@ -44,7 +54,7 @@ export function getMessagePreviewText(message: ChatMessage, visibleText?: string
|
||||
return `📊 Опрос: ${message.poll.question}`;
|
||||
}
|
||||
const text = getMessageCopyText(message, visibleText);
|
||||
if (text) return text;
|
||||
if (text && !looksLikeEncryptedPayload(text)) return text;
|
||||
if (message.type === 'IMAGE') return '📷 Фото';
|
||||
if (message.type === 'VOICE') return '🎤 Голосовое';
|
||||
if (message.type === 'AUDIO') return '🎵 Аудио';
|
||||
|
||||
55
apps/frontend/lib/embedded-auth-bridge.ts
Normal file
55
apps/frontend/lib/embedded-auth-bridge.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AUTH_REFRESH_KEY, AUTH_SESSION_KEY, AUTH_TOKEN_KEY } from '@/lib/api';
|
||||
|
||||
export const EMBEDDED_AUTH_MESSAGE = 'lendry-id-embedded-auth';
|
||||
|
||||
export interface EmbeddedAuthPayload {
|
||||
type: typeof EMBEDDED_AUTH_MESSAGE;
|
||||
token: string;
|
||||
refreshToken?: string;
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export function postEmbeddedAuthToIframe(iframe: HTMLIFrameElement, auth: { token: string; refreshToken?: string | null; sessionId?: string | null }) {
|
||||
const target = iframe.contentWindow;
|
||||
if (!target || !auth.token) return;
|
||||
const payload: EmbeddedAuthPayload = {
|
||||
type: EMBEDDED_AUTH_MESSAGE,
|
||||
token: auth.token,
|
||||
refreshToken: auth.refreshToken ?? undefined,
|
||||
sessionId: auth.sessionId ?? undefined
|
||||
};
|
||||
target.postMessage(payload, window.location.origin);
|
||||
}
|
||||
|
||||
export function useEmbeddedAuthFallback() {
|
||||
const [embeddedToken, setEmbeddedToken] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
function handleMessage(event: MessageEvent) {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
const data = event.data as Partial<EmbeddedAuthPayload> | null;
|
||||
if (!data || data.type !== EMBEDDED_AUTH_MESSAGE || !data.token?.trim()) return;
|
||||
|
||||
const token = data.token.trim();
|
||||
setEmbeddedToken(token);
|
||||
window.localStorage.setItem(AUTH_TOKEN_KEY, token);
|
||||
if (data.refreshToken) {
|
||||
window.localStorage.setItem(AUTH_REFRESH_KEY, data.refreshToken);
|
||||
}
|
||||
if (data.sessionId) {
|
||||
window.localStorage.setItem(AUTH_SESSION_KEY, data.sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
if (window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'lendry-id-embedded-auth-request' }, window.location.origin);
|
||||
}
|
||||
return () => window.removeEventListener('message', handleMessage);
|
||||
}, []);
|
||||
|
||||
return embeddedToken;
|
||||
}
|
||||
Reference in New Issue
Block a user