fix and update
This commit is contained in:
@@ -3,7 +3,6 @@ import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
|||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import { CoreGrpcService } from '../core-grpc.service';
|
import { CoreGrpcService } from '../core-grpc.service';
|
||||||
import { buildFedcmWebIdentityManifest, resolveFedcmEndpoints } from '../lib/fedcm-config';
|
import { buildFedcmWebIdentityManifest, resolveFedcmEndpoints } from '../lib/fedcm-config';
|
||||||
import { assertFedcmWebIdentityRequest } from '../lib/fedcm-cors';
|
|
||||||
import { buildOpenIdConfiguration, resolveOAuthIssuer } from '../lib/oauth-issuer';
|
import { buildOpenIdConfiguration, resolveOAuthIssuer } from '../lib/oauth-issuer';
|
||||||
|
|
||||||
@ApiTags('OpenID Connect')
|
@ApiTags('OpenID Connect')
|
||||||
@@ -17,9 +16,11 @@ export class WellKnownController {
|
|||||||
description: 'Манифест Federated Credential Management API, указывающий на конфигурацию провайдера.'
|
description: 'Манифест Federated Credential Management API, указывающий на конфигурацию провайдера.'
|
||||||
})
|
})
|
||||||
async webIdentity(@Req() req: Request, @Res({ passthrough: true }) res: Response) {
|
async webIdentity(@Req() req: Request, @Res({ passthrough: true }) res: Response) {
|
||||||
assertFedcmWebIdentityRequest(req);
|
// Публичный discovery-манифест: без Sec-Fetch-Dest проверки (браузер FedCM шлёт
|
||||||
|
// webidentity или empty; ручной заход с document не должен ломать One Tap).
|
||||||
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
||||||
res.setHeader('Cache-Control', 'public, max-age=300');
|
res.setHeader('Cache-Control', 'public, max-age=300');
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
const endpoints = await resolveFedcmEndpoints(this.core, req);
|
const endpoints = await resolveFedcmEndpoints(this.core, req);
|
||||||
return buildFedcmWebIdentityManifest(endpoints);
|
return buildFedcmWebIdentityManifest(endpoints);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,34 @@ export function applyFedcmPreflightHeaders(res: Response, origin?: string) {
|
|||||||
res.setHeader('Access-Control-Max-Age', '86400');
|
res.setHeader('Access-Control-Max-Age', '86400');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FedCM-запросы должны иметь Sec-Fetch-Dest: webidentity (или empty, если прокси
|
||||||
|
* не пробрасывает заголовок). Блокируем только явно «не-FedCM» dest (document,
|
||||||
|
* script, image…) — иначе well-known/config отдают 400 и One Tap ломается.
|
||||||
|
*/
|
||||||
|
const BLOCKED_FEDCM_FETCH_DEST = new Set([
|
||||||
|
'document',
|
||||||
|
'embed',
|
||||||
|
'frame',
|
||||||
|
'iframe',
|
||||||
|
'object',
|
||||||
|
'script',
|
||||||
|
'style',
|
||||||
|
'image',
|
||||||
|
'font',
|
||||||
|
'audio',
|
||||||
|
'video',
|
||||||
|
'track',
|
||||||
|
'worker',
|
||||||
|
'serviceworker',
|
||||||
|
'sharedworker',
|
||||||
|
'manifest',
|
||||||
|
'xslt'
|
||||||
|
]);
|
||||||
|
|
||||||
export function assertFedcmWebIdentityRequest(req: Request) {
|
export function assertFedcmWebIdentityRequest(req: Request) {
|
||||||
const dest = String(req.headers['sec-fetch-dest'] ?? '').toLowerCase();
|
const dest = String(req.headers['sec-fetch-dest'] ?? '').toLowerCase();
|
||||||
if (dest && dest !== 'webidentity') {
|
if (dest && BLOCKED_FEDCM_FETCH_DEST.has(dest)) {
|
||||||
throw new BadRequestException('Недопустимый Sec-Fetch-Dest для FedCM');
|
throw new BadRequestException('Недопустимый Sec-Fetch-Dest для FedCM');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user