fix and update
This commit is contained in:
@@ -40,6 +40,7 @@ type FedcmAccountsResponse = {
|
|||||||
given_name?: string;
|
given_name?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
picture?: string;
|
picture?: string;
|
||||||
|
tel?: string;
|
||||||
approved_clients?: string[];
|
approved_clients?: string[];
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -105,15 +105,20 @@ export async function resolveFedcmEndpoints(core: CoreGrpcService, _req?: Reques
|
|||||||
|
|
||||||
export function buildFedcmProviderConfig(endpoints: FedcmEndpoints) {
|
export function buildFedcmProviderConfig(endpoints: FedcmEndpoints) {
|
||||||
const base = normalizePublicBaseUrl(endpoints.issuer);
|
const base = normalizePublicBaseUrl(endpoints.issuer);
|
||||||
|
const front = normalizePublicBaseUrl(endpoints.frontendUrl);
|
||||||
return {
|
return {
|
||||||
accounts_endpoint: `${base}/fedcm/accounts`,
|
accounts_endpoint: `${base}/fedcm/accounts`,
|
||||||
client_metadata_endpoint: `${base}/fedcm/client_metadata`,
|
client_metadata_endpoint: `${base}/fedcm/client_metadata`,
|
||||||
id_assertion_endpoint: `${base}/fedcm/id_assertion`,
|
id_assertion_endpoint: `${base}/fedcm/id_assertion`,
|
||||||
login_url: endpoints.loginUrl,
|
login_url: endpoints.loginUrl,
|
||||||
branding: {
|
branding: {
|
||||||
|
name: endpoints.projectName,
|
||||||
background_color: '#ffffff',
|
background_color: '#ffffff',
|
||||||
color: '#1f2430',
|
color: '#1f2430',
|
||||||
icons: [{ url: `${base}/favicon.ico`, size: 32 }]
|
icons: [
|
||||||
|
{ url: `${front}/icon.svg`, size: 40 },
|
||||||
|
{ url: `${base}/favicon.ico`, size: 32 }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -135,7 +140,9 @@ export function buildFedcmDiscoverPayload(endpoints: FedcmEndpoints, enabled = t
|
|||||||
configUrl: endpoints.configUrl,
|
configUrl: endpoints.configUrl,
|
||||||
webIdentityUrl: endpoints.webIdentityUrl,
|
webIdentityUrl: endpoints.webIdentityUrl,
|
||||||
accountsEndpoint: endpoints.accountsEndpoint,
|
accountsEndpoint: endpoints.accountsEndpoint,
|
||||||
loginUrl: endpoints.loginUrl
|
loginUrl: endpoints.loginUrl,
|
||||||
|
// Поля для navigator.credentials.get({ identity: { fields: [...] } }) на стороне RP (Chrome 132+).
|
||||||
|
suggestedFields: ['name', 'email', 'picture', 'tel']
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ async function loginWithFedCM() {
|
|||||||
identity: {
|
identity: {
|
||||||
providers: [{
|
providers: [{
|
||||||
configURL: '${fedcmConfigUrl}',
|
configURL: '${fedcmConfigUrl}',
|
||||||
clientId: '${clientIdPlaceholder}'
|
clientId: '${clientIdPlaceholder}',
|
||||||
|
fields: ['name', 'email', 'picture', 'tel']
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
mediation: 'optional'
|
mediation: 'optional'
|
||||||
|
|||||||
@@ -104,6 +104,10 @@ export function OAuthClientOneTapSection({
|
|||||||
<code>configURL</code> для FedCM: <code>{endpoints.fedcmConfigUrl}</code> (не{' '}
|
<code>configURL</code> для FedCM: <code>{endpoints.fedcmConfigUrl}</code> (не{' '}
|
||||||
<code>{frontendBase}/idp-api/fedcm/config.json</code>).
|
<code>{frontendBase}/idp-api/fedcm/config.json</code>).
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
Для disclosure (имя, email, аватар, телефон) RP должен передавать{' '}
|
||||||
|
<code>{`fields: ['name', 'email', 'picture', 'tel']`}</code> в вызове FedCM (Chrome 132+).
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
При ошибке NetworkError проверьте, что <code>PUBLIC_API_URL</code> = <code>{endpoints.issuer}</code>.
|
При ошибке NetworkError проверьте, что <code>PUBLIC_API_URL</code> = <code>{endpoints.issuer}</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ export function buildOneTapExamples(urls: OneTapUrls, clientId: string, redirect
|
|||||||
identity: {
|
identity: {
|
||||||
providers: [{
|
providers: [{
|
||||||
configURL: '${fedcmConfigUrl}',
|
configURL: '${fedcmConfigUrl}',
|
||||||
clientId: '${clientId}'
|
clientId: '${clientId}',
|
||||||
|
// Chrome 132+: disclosure в диалоге FedCM (имя, email, аватар, телефон)
|
||||||
|
fields: ['name', 'email', 'picture', 'tel']
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
mediation: 'optional'
|
mediation: 'optional'
|
||||||
|
|||||||
@@ -95,7 +95,8 @@
|
|||||||
{
|
{
|
||||||
configURL: configUrl,
|
configURL: configUrl,
|
||||||
configUrl: configUrl,
|
configUrl: configUrl,
|
||||||
clientId: clientId
|
clientId: clientId,
|
||||||
|
fields: ['name', 'email', 'picture', 'tel']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
|
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
import { PrismaService } from '../infra/prisma.service';
|
import { PrismaService } from '../infra/prisma.service';
|
||||||
|
import { MediaService } from './media.service';
|
||||||
import { OAuthCoreService } from './oauth-core.service';
|
import { OAuthCoreService } from './oauth-core.service';
|
||||||
import { SessionService } from './session.service';
|
import { SessionService } from './session.service';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
@@ -11,7 +12,8 @@ export class FedcmService {
|
|||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
private readonly session: SessionService,
|
private readonly session: SessionService,
|
||||||
private readonly oauthCore: OAuthCoreService,
|
private readonly oauthCore: OAuthCoreService,
|
||||||
private readonly settings: SettingsService
|
private readonly settings: SettingsService,
|
||||||
|
private readonly media: MediaService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getAccounts(userId: string, sessionId: string) {
|
async getAccounts(userId: string, sessionId: string) {
|
||||||
@@ -35,6 +37,9 @@ export class FedcmService {
|
|||||||
.map((item) => item.client.clientId);
|
.map((item) => item.client.clientId);
|
||||||
|
|
||||||
const givenName = user.displayName.trim().split(/\s+/)[0] || user.displayName;
|
const givenName = user.displayName.trim().split(/\s+/)[0] || user.displayName;
|
||||||
|
const picture = await this.media.createFedcmAvatarUrl(user.id);
|
||||||
|
const email = user.email?.trim() || undefined;
|
||||||
|
const tel = user.phone?.trim() || undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts: [
|
accounts: [
|
||||||
@@ -42,8 +47,9 @@ export class FedcmService {
|
|||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.displayName,
|
name: user.displayName,
|
||||||
given_name: givenName,
|
given_name: givenName,
|
||||||
email: user.email ?? undefined,
|
email,
|
||||||
picture: user.avatarUrl ?? undefined,
|
picture,
|
||||||
|
tel,
|
||||||
approved_clients: approvedClients
|
approved_clients: approvedClients
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -68,6 +68,25 @@ export class MediaService {
|
|||||||
return { userId, hasAvatar: true };
|
return { userId, hasAvatar: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createFedcmAvatarUrl(userId: string): Promise<string | undefined> {
|
||||||
|
const user = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||||
|
if (!user) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const legacyUrl = user.avatarUrl?.trim();
|
||||||
|
if (legacyUrl) {
|
||||||
|
return legacyUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.avatarStorageKey) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { accessUrl } = await this.createStreamAccessUrl(user.avatarStorageKey, userId);
|
||||||
|
return accessUrl;
|
||||||
|
}
|
||||||
|
|
||||||
async getAvatarAccessUrl(requesterId: string, targetUserId: string) {
|
async getAvatarAccessUrl(requesterId: string, targetUserId: string) {
|
||||||
const user = await this.prisma.user.findUnique({ where: { id: targetUserId } });
|
const user = await this.prisma.user.findUnique({ where: { id: targetUserId } });
|
||||||
if (!user?.avatarStorageKey) {
|
if (!user?.avatarStorageKey) {
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ message FedcmAccount {
|
|||||||
optional string email = 4;
|
optional string email = 4;
|
||||||
optional string picture = 5;
|
optional string picture = 5;
|
||||||
repeated string approved_clients = 6;
|
repeated string approved_clients = 6;
|
||||||
|
optional string tel = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message FedcmAccountsResponse {
|
message FedcmAccountsResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user