Add secure configuration bootstrap flow

This commit is contained in:
Lorenzune
2026-04-25 13:29:48 +02:00
parent 6c7d78c156
commit 3c9a599505
27 changed files with 962 additions and 3616 deletions
+2 -2
View File
@@ -31,8 +31,8 @@ const cacheBustUrl = (path: string): string =>
(window as any).NitroClientMode = clientMode;
(window as any).NitroConfig = {
'config.urls': [
clientMode.secureAssetsEnabled ? secureUrl('config', 'renderer-config.json', true) : cacheBustUrl('renderer-config.json'),
clientMode.secureAssetsEnabled ? secureUrl('config', 'ui-config.json', true) : cacheBustUrl('ui-config.json')
clientMode.secureAssetsEnabled ? secureUrl('config', 'renderer-config.json', true) : cacheBustUrl('configuration/renderer-config.json'),
clientMode.secureAssetsEnabled ? secureUrl('config', 'ui-config.json', true) : cacheBustUrl('configuration/ui-config.json')
],
'sso.ticket': search.get('sso') || null,
'forward.type': search.get('room') ? 2 : -1,
+3 -2
View File
@@ -1,6 +1,7 @@
import { FC, useEffect, useRef, useState } from 'react';
import { GetConfigurationValue } from '../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { configFileUrl } from '../../secure-assets';
interface AdsenseConfig {
slot: string;
@@ -70,7 +71,7 @@ export const GoogleAdsView: FC<{}> = () => {
try {
const [ adsTxtRes, configRes ] = await Promise.all([
fetch('/ads.txt', { cache: 'no-cache' }),
fetch('/adsense.json', { cache: 'no-cache' })
fetch(configFileUrl('adsense.json', true), { cache: 'no-cache' })
]);
if (!adsTxtRes.ok) throw new Error(`ads.txt ${ adsTxtRes.status }`);
@@ -156,7 +157,7 @@ export const GoogleAdsView: FC<{}> = () => {
data-full-width-responsive={ (config.fullWidthResponsive ?? true) ? 'true' : 'false' }
/> }
{ !loadError && publisherId && config && !config.slot &&
<div className="text-xs text-gray-500 text-center px-2">Ad slot not configured in adsense.json</div> }
<div className="text-xs text-gray-500 text-center px-2">Ad slot not configured in configuration/adsense.json</div> }
</div>
</NitroCardContentView>
</NitroCardView>
+2 -1
View File
@@ -1,6 +1,7 @@
import { GetConfiguration } from '@nitrots/nitro-renderer';
import { FC, FormEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ClearRememberLogin, GetConfigurationValue, GetRememberLogin, StoreRememberLoginFromPayload } from '../../api';
import { configFileUrl } from '../../secure-assets';
import flagBr from '../../assets/images/flag_icon/flag_icon_br.png';
import flagDe from '../../assets/images/flag_icon/flag_icon_de.png';
import flagEn from '../../assets/images/flag_icon/flag_icon_en.png';
@@ -1054,7 +1055,7 @@ const RegisterDialog: FC<RegisterDialogProps> = props =>
{
if(step !== 'avatar' || hotLooks.length) return;
let cancelled = false;
fetch('hotlooks.json', { credentials: 'omit' })
fetch(configFileUrl('hotlooks.json', true), { credentials: 'omit' })
.then(r => r.ok ? r.json() : null)
.then((json: unknown) =>
{
+12 -1
View File
@@ -204,7 +204,7 @@ const getPlainAssetBase = (kind: 'config' | 'gamedata'): string =>
if(typeof configured === 'string' && configured.length) return configured.endsWith('/') ? configured : `${ configured }/`;
if(kind === 'config') return `${ window.location.origin }/`;
if(kind === 'config') return `${ window.location.origin }/configuration/`;
return `${ window.location.origin }/nitro/gamedata/`;
};
@@ -239,6 +239,17 @@ export const secureUrl = (kind: 'config' | 'gamedata', file: string, cacheBust =
return `${ base }/nitro-sec/file?kind=${ encodeURIComponent(kind) }&file=${ encodeURIComponent(file) }${ version }`;
};
export const configFileUrl = (file: string, cacheBust = false): string =>
{
if(getClientMode().secureAssetsEnabled) return secureUrl('config', file, cacheBust);
const plainUrl = new URL(`configuration/${ file.replace(/^\/+/, '') }`, `${ window.location.origin }/`);
if(cacheBust) plainUrl.searchParams.set('v', Date.now().toString(36));
return plainUrl.toString();
};
const createSecureSession = async (): Promise<SecureSession> =>
{
setDebugState('secure: generating ECDH session');