22// SPDX-License-Identifier: Apache-2.0
33// SPDX-License-Identifier: MIT
44
5- use crate :: embedded_assets:: { AssetOptions , EmbeddedAssets , EmbeddedAssetsError } ;
5+ use std:: ffi:: OsStr ;
6+ use std:: path:: { Path , PathBuf } ;
7+
68use proc_macro2:: TokenStream ;
79use quote:: quote;
8- use std:: path:: { Path , PathBuf } ;
9- use tauri_utils:: config:: { AppUrl , Config , WindowUrl } ;
10+ use sha2:: { Digest , Sha256 } ;
11+
12+ use tauri_utils:: assets:: AssetKey ;
13+ use tauri_utils:: config:: { AppUrl , Config , PatternKind , WindowUrl } ;
14+ use tauri_utils:: html:: { inject_nonce_token, parse as parse_html, NodeRef , PatternObject } ;
15+
16+ use crate :: embedded_assets:: { AssetOptions , CspHashes , EmbeddedAssets , EmbeddedAssetsError } ;
1017
1118/// Necessary data needed by [`context_codegen`] to generate code for a Tauri application context.
1219pub struct ContextData {
@@ -16,6 +23,81 @@ pub struct ContextData {
1623 pub root : TokenStream ,
1724}
1825
26+ fn load_csp ( document : & mut NodeRef , key : & AssetKey , csp_hashes : & mut CspHashes ) {
27+ #[ cfg( target_os = "linux" ) ]
28+ :: tauri_utils:: html:: inject_csp_token ( document) ;
29+ inject_nonce_token ( document) ;
30+ if let Ok ( inline_script_elements) = document. select ( "script:not(empty)" ) {
31+ let mut scripts = Vec :: new ( ) ;
32+ for inline_script_el in inline_script_elements {
33+ let script = inline_script_el. as_node ( ) . text_contents ( ) ;
34+ let mut hasher = Sha256 :: new ( ) ;
35+ hasher. update ( & script) ;
36+ let hash = hasher. finalize ( ) ;
37+ scripts. push ( format ! ( "'sha256-{}'" , base64:: encode( & hash) ) ) ;
38+ }
39+ csp_hashes
40+ . inline_scripts
41+ . entry ( key. clone ( ) . into ( ) )
42+ . or_default ( )
43+ . append ( & mut scripts) ;
44+ }
45+ }
46+
47+ fn map_core_assets (
48+ options : & AssetOptions ,
49+ ) -> impl Fn ( & AssetKey , & Path , & mut Vec < u8 > , & mut CspHashes ) -> Result < ( ) , EmbeddedAssetsError > {
50+ #[ allow( unused_variables) ]
51+ let pattern = PatternObject :: from ( & options. pattern ) ;
52+ let csp = options. csp ;
53+ move |key, path, input, csp_hashes| {
54+ if path. extension ( ) == Some ( OsStr :: new ( "html" ) ) {
55+ let mut document = parse_html ( String :: from_utf8_lossy ( input) . into_owned ( ) ) ;
56+
57+ if csp {
58+ load_csp ( & mut document, key, csp_hashes) ;
59+
60+ #[ cfg( feature = "isolation" ) ]
61+ if let PatternObject :: Isolation { .. } = & pattern {
62+ // create the csp for the isolation iframe styling now, to make the runtime less complex
63+ let mut hasher = Sha256 :: new ( ) ;
64+ hasher. update ( tauri_utils:: pattern:: isolation:: IFRAME_STYLE ) ;
65+ let hash = hasher. finalize ( ) ;
66+ csp_hashes
67+ . styles
68+ . push ( format ! ( "'sha256-{}'" , base64:: encode( & hash) ) ) ;
69+ }
70+ }
71+
72+ * input = document. to_string ( ) . as_bytes ( ) . to_vec ( ) ;
73+ }
74+ Ok ( ( ) )
75+ }
76+ }
77+
78+ #[ cfg( feature = "isolation" ) ]
79+ fn map_isolation (
80+ _options : & AssetOptions ,
81+ dir : PathBuf ,
82+ ) -> impl Fn ( & AssetKey , & Path , & mut Vec < u8 > , & mut CspHashes ) -> Result < ( ) , EmbeddedAssetsError > {
83+ move |_key, path, input, _csp_hashes| {
84+ if path. extension ( ) == Some ( OsStr :: new ( "html" ) ) {
85+ let mut isolation_html =
86+ tauri_utils:: html:: parse ( String :: from_utf8_lossy ( input) . into_owned ( ) ) ;
87+
88+ // this is appended, so no need to reverse order it
89+ tauri_utils:: html:: inject_codegen_isolation_script ( & mut isolation_html) ;
90+
91+ // temporary workaround for windows not loading assets
92+ tauri_utils:: html:: inline_isolation ( & mut isolation_html, & dir) ;
93+
94+ * input = isolation_html. to_string ( ) . as_bytes ( ) . to_vec ( )
95+ }
96+
97+ Ok ( ( ) )
98+ }
99+ }
100+
19101/// Build a `tauri::Context` for including in application code.
20102pub fn context_codegen ( data : ContextData ) -> Result < TokenStream , EmbeddedAssetsError > {
21103 let ContextData {
@@ -25,7 +107,8 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
25107 root,
26108 } = data;
27109
28- let mut options = AssetOptions :: new ( ) ;
110+ let mut options = AssetOptions :: new ( config. tauri . pattern . clone ( ) )
111+ . freeze_prototype ( config. tauri . security . freeze_prototype ) ;
29112 let csp = if dev {
30113 config
31114 . tauri
@@ -64,7 +147,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
64147 path
65148 )
66149 }
67- EmbeddedAssets :: new ( assets_path, options) ?
150+ EmbeddedAssets :: new ( assets_path, map_core_assets ( & options) ) ?
68151 }
69152 _ => unimplemented ! ( ) ,
70153 } ,
@@ -73,7 +156,7 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
73156 . iter ( )
74157 . map ( |p| config_parent. join ( p) )
75158 . collect :: < Vec < _ > > ( ) ,
76- options,
159+ map_core_assets ( & options) ,
77160 ) ?,
78161 _ => unimplemented ! ( ) ,
79162 } ;
@@ -180,14 +263,39 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
180263 #[ cfg( not( target_os = "macos" ) ) ]
181264 let info_plist = quote ! ( ( ) ) ;
182265
183- // double braces are purposeful to force the code into a block expression
266+ let pattern = match & options. pattern {
267+ PatternKind :: Brownfield => quote ! ( #root:: Pattern :: Brownfield ( std:: marker:: PhantomData ) ) ,
268+ #[ cfg( feature = "isolation" ) ]
269+ PatternKind :: Isolation { dir } => {
270+ let dir = config_parent. join ( dir) ;
271+ if !dir. exists ( ) {
272+ panic ! (
273+ "The isolation dir configuration is set to `{:?}` but this path doesn't exist" ,
274+ dir
275+ )
276+ }
277+
278+ let key = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
279+ let assets = EmbeddedAssets :: new ( dir. clone ( ) , map_isolation ( & options, dir) ) ?;
280+ let schema = options. isolation_schema ;
281+
282+ quote ! ( #root:: Pattern :: Isolation {
283+ assets: :: std:: sync:: Arc :: new( #assets) ,
284+ schema: #schema. into( ) ,
285+ key: #key. into( ) ,
286+ crypto_keys: std:: boxed:: Box :: new( :: tauri:: utils:: pattern:: isolation:: Keys :: new( ) . expect( "unable to generate cryptographically secure keys for Tauri \" Isolation\" Pattern" ) ) ,
287+ } )
288+ }
289+ } ;
290+
184291 Ok ( quote ! ( #root:: Context :: new(
185292 #config,
186293 :: std:: sync:: Arc :: new( #assets) ,
187294 #default_window_icon,
188295 #system_tray_icon,
189296 #package_info,
190297 #info_plist,
298+ #pattern
191299 ) ) )
192300}
193301
0 commit comments