fix and update
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { CoreGrpcService } from '../core-grpc.service';
|
import { CoreGrpcService } from '../core-grpc.service';
|
||||||
import { normalizePublicBaseUrl, pickBestPublicBase, isInternalHostname } from './public-url';
|
import { normalizePublicBaseUrl, pickBestPublicBase, isInternalHostname, normalizeDedicatedApiIssuer } from './public-url';
|
||||||
|
|
||||||
function normalizeBaseUrl(url: string) {
|
function normalizeBaseUrl(url: string) {
|
||||||
return normalizePublicBaseUrl(url);
|
return normalizePublicBaseUrl(url);
|
||||||
@@ -52,7 +52,8 @@ export async function resolveOAuthIssuer(core: CoreGrpcService, fallback = 'http
|
|||||||
|
|
||||||
const fromDomain = await resolveProjectDomainUrl(core, true);
|
const fromDomain = await resolveProjectDomainUrl(core, true);
|
||||||
// env первым: в Docker .env перекрывает seed localhost в БД после первого деплоя.
|
// env первым: в Docker .env перекрывает seed localhost в БД после первого деплоя.
|
||||||
return pickBestPublicBase([envIssuer, fromDb, fromDomain], fallback);
|
const picked = pickBestPublicBase([envIssuer, fromDb, fromDomain], fallback);
|
||||||
|
return normalizeDedicatedApiIssuer(picked);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveFrontendUrl(core: CoreGrpcService, fallback = 'http://localhost:3002'): Promise<string> {
|
export async function resolveFrontendUrl(core: CoreGrpcService, fallback = 'http://localhost:3002'): Promise<string> {
|
||||||
|
|||||||
@@ -17,6 +17,25 @@ export function normalizePublicBaseUrl(url: string) {
|
|||||||
return url.trim().replace(/\/+$/, '');
|
return url.trim().replace(/\/+$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* На выделенном API-домене (api.example.com) gateway слушает в корне (/fedcm, /oauth).
|
||||||
|
* Префикс /idp-api нужен только на SSO-домене. Убираем лишний суффикс из PUBLIC_API_URL.
|
||||||
|
*/
|
||||||
|
export function normalizeDedicatedApiIssuer(url: string) {
|
||||||
|
const normalized = normalizePublicBaseUrl(url);
|
||||||
|
try {
|
||||||
|
const parsed = new URL(normalized);
|
||||||
|
const host = parsed.hostname.toLowerCase();
|
||||||
|
const path = parsed.pathname.replace(/\/+$/, '') || '/';
|
||||||
|
if (host.startsWith('api.') && (path === '/idp-api' || path.endsWith('/idp-api'))) {
|
||||||
|
return `${parsed.protocol}//${parsed.host}`;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
export function isInternalHostname(hostname: string) {
|
export function isInternalHostname(hostname: string) {
|
||||||
const host = hostname.trim().toLowerCase();
|
const host = hostname.trim().toLowerCase();
|
||||||
if (!host) {
|
if (!host) {
|
||||||
|
|||||||
51
install.sh
51
install.sh
@@ -2312,9 +2312,32 @@ EOF
|
|||||||
|
|
||||||
build_nginx_api_location_block() {
|
build_nginx_api_location_block() {
|
||||||
if [[ "$NGINX_MODE" == "docker" ]]; then
|
if [[ "$NGINX_MODE" == "docker" ]]; then
|
||||||
local proxy
|
local proxy proxy_idp proxy_ws
|
||||||
proxy="$(render_proxy_root api)"
|
proxy="$(render_proxy_root api)"
|
||||||
|
proxy_idp="$(render_proxy_idp_api)"
|
||||||
|
proxy_ws="$(render_proxy_idp_ws)"
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
# Алиас /idp-api на API-домене: совместимость с PUBLIC_API_URL из документации и curl.
|
||||||
|
location ^~ /idp-api/ws {
|
||||||
|
${proxy_ws}
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade \$http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||||
|
proxy_read_timeout 86400s;
|
||||||
|
proxy_connect_timeout 5s;
|
||||||
|
proxy_next_upstream error timeout http_502 http_503 http_504;
|
||||||
|
proxy_next_upstream_tries 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /idp-api/ {
|
||||||
|
${proxy_idp}
|
||||||
|
${nginx_proxy_headers_api}
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
${proxy}
|
${proxy}
|
||||||
${nginx_proxy_headers_api}
|
${nginx_proxy_headers_api}
|
||||||
@@ -3031,6 +3054,25 @@ verify_fedcm_endpoints() {
|
|||||||
echo -e " ${YELLOW}!${NC} FedCM discover.json → HTTP ${code} (${api_domain}, ожидалось 200)"
|
echo -e " ${YELLOW}!${NC} FedCM discover.json → HTTP ${code} (${api_domain}, ожидалось 200)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local config_login_url config_login_url_alias
|
||||||
|
config_login_url="$(curl ${curl_extra} -fsS --max-time 8 \
|
||||||
|
-H "Sec-Fetch-Dest: webidentity" \
|
||||||
|
"${scheme}://${api_domain}/fedcm/config.json" 2>/dev/null \
|
||||||
|
| jq -r '.login_url // empty' 2>/dev/null || true)"
|
||||||
|
config_login_url_alias="$(curl ${curl_extra} -fsS --max-time 8 \
|
||||||
|
-H "Sec-Fetch-Dest: webidentity" \
|
||||||
|
"${scheme}://${api_domain}/idp-api/fedcm/config.json" 2>/dev/null \
|
||||||
|
| jq -r '.login_url // empty' 2>/dev/null || true)"
|
||||||
|
if [[ -n "$config_login_url" ]]; then
|
||||||
|
echo -e " ${GREEN}✔${NC} FedCM config.json login_url=${config_login_url}"
|
||||||
|
elif [[ -n "$config_login_url_alias" ]]; then
|
||||||
|
echo -e " ${YELLOW}!${NC} FedCM config.json: используйте ${scheme}://${api_domain}/fedcm/config.json (не /idp-api/ на API-домене)"
|
||||||
|
echo -e " ${GREEN}✔${NC} FedCM config.json (alias /idp-api) login_url=${config_login_url_alias}"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✘${NC} FedCM config.json без login_url (${api_domain}) — проверьте PUBLIC_FRONTEND_URL и api-gateway"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
apex_domain="$(registrable_domain "${frontend_domain:-$api_domain}")"
|
apex_domain="$(registrable_domain "${frontend_domain:-$api_domain}")"
|
||||||
if [[ -z "$apex_domain" \
|
if [[ -z "$apex_domain" \
|
||||||
|| "$apex_domain" == "$frontend_domain" \
|
|| "$apex_domain" == "$frontend_domain" \
|
||||||
@@ -3043,6 +3085,13 @@ verify_fedcm_endpoints() {
|
|||||||
body="$(curl ${curl_extra} -fsS --max-time 8 "${scheme}://${apex_domain}/.well-known/web-identity" 2>/dev/null || true)"
|
body="$(curl ${curl_extra} -fsS --max-time 8 "${scheme}://${apex_domain}/.well-known/web-identity" 2>/dev/null || true)"
|
||||||
if [[ "$code" == "200" && "$body" == *provider_urls* ]]; then
|
if [[ "$code" == "200" && "$body" == *provider_urls* ]]; then
|
||||||
echo -e " ${GREEN}✔${NC} FedCM web-identity → 200 (${apex_domain})"
|
echo -e " ${GREEN}✔${NC} FedCM web-identity → 200 (${apex_domain})"
|
||||||
|
local well_known_login config_login
|
||||||
|
well_known_login="$(printf '%s' "$body" | jq -r '.login_url // empty' 2>/dev/null || true)"
|
||||||
|
config_login="${config_login_url:-$config_login_url_alias}"
|
||||||
|
if [[ -n "$well_known_login" && -n "$config_login" && "$well_known_login" != "$config_login" ]]; then
|
||||||
|
echo -e " ${RED}✘${NC} FedCM login_url не совпадает: web-identity=${well_known_login}, config.json=${config_login}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
elif [[ "$code" == "000" ]]; then
|
elif [[ "$code" == "000" ]]; then
|
||||||
echo -e " ${RED}✘${NC} FedCM web-identity недоступен (${apex_domain}) — ERR_CERT или DNS"
|
echo -e " ${RED}✘${NC} FedCM web-identity недоступен (${apex_domain}) — ERR_CERT или DNS"
|
||||||
|
|||||||
Reference in New Issue
Block a user