@@ -562,6 +562,57 @@ export class WindowsProjectService
562562 catch ( err ) {
563563 this . $logger . warn ( `dotnet-tool check failed: ${ err } ` ) ;
564564 }
565+
566+ // Source protection: seal the just-written webpack output (app/) into an encrypted
567+ // app.nsbundle via nsbundle_pack.
568+ // Release builds only — HMR/LiveSync dev builds patch app/ incrementally, which a sealed
569+ // container can't do, and --release/--hmr are already mutually exclusive CLI flags.
570+ // Never fatal: a missing tool or failed pack just leaves the plaintext app/ folder, which
571+ // the .csproj already falls back to via Condition="Exists('app.nsbundle')".
572+ try {
573+ const isRelease = ! ! ( _prepareData as any ) ?. release ;
574+ const wantsSourceProtect =
575+ ( this . $options as any ) . sourceProtect ??
576+ projectData ?. nsConfig ?. windows ?. sourceProtect ??
577+ false ;
578+ if ( isRelease && wantsSourceProtect ) {
579+ const arch = process . arch === "arm64" ? "arm64" : "x64" ;
580+ const packCandidates = [
581+ process . env . NSBUNDLE_PACK_PATH ,
582+ path . join ( platformData . projectRoot , "tools" , `nsbundle_pack-${ arch } .exe` ) ,
583+ path . join ( platformData . projectRoot , "tools" , "nsbundle_pack.exe" ) ,
584+ ] . filter ( Boolean as any ) ;
585+ let packExe : string | null = null ;
586+ for ( const p of packCandidates ) {
587+ if ( p && fs . existsSync ( p ) ) { packExe = p as string ; break ; }
588+ }
589+ if ( packExe ) {
590+ const keyHex =
591+ ( this . $options as any ) . sourceProtectKeyHex ||
592+ process . env . NS_WINDOWS_BUNDLE_KEY ;
593+ const args = [
594+ "--input" , path . join ( appProjectDir , "app" ) ,
595+ "--output" , path . join ( appProjectDir , "app.nsbundle" ) ,
596+ ] ;
597+ if ( keyHex ) { args . push ( "--key-hex" , keyHex ) ; }
598+ this . $logger . info ( `Running nsbundle_pack (source protection): ${ packExe } ` ) ;
599+ try {
600+ const result = await this . $childProcess . spawnFromEvent ( packExe , args , "close" , { cwd : platformData . projectRoot } , { throwError : false } ) ;
601+ if ( result && result . stdout ) { this . $logger . info ( result . stdout ) ; }
602+ }
603+ catch ( err ) {
604+ this . $logger . warn ( `nsbundle_pack execution failed: ${ err } ` ) ;
605+ }
606+ }
607+ else {
608+ this . $logger . info ( "Source protection requested but nsbundle_pack.exe was not found under tools/ — skipping (plaintext app/ will be packaged)." ) ;
609+ }
610+ }
611+ }
612+ catch ( err ) {
613+ this . $logger . warn ( `Source protection check failed: ${ err } ` ) ;
614+ }
615+
565616 const pluginsDir = path . join ( appProjectDir , "plugins" ) ;
566617
567618 // Ensure plugins directory exists inside the platform app folder (where csproj expects it)
0 commit comments