@@ -6,8 +6,13 @@ use crate::licensing::validation_client::{activate_short_code, is_short_code};
66use base64:: { Engine , engine:: general_purpose:: STANDARD as BASE64 } ;
77use ed25519_dalek:: { Signature , Verifier , VerifyingKey } ;
88use serde:: { Deserialize , Serialize } ;
9+ use std:: sync:: Mutex ;
910use tauri_plugin_store:: StoreExt ;
1011
12+ /// In-memory cache for verified license info. Avoids re-parsing and re-verifying
13+ /// the Ed25519 signature on every call to `get_license_info`.
14+ static LICENSE_CACHE : Mutex < Option < LicenseInfo > > = Mutex :: new ( None ) ;
15+
1116// Ed25519 public key (32 bytes, hex-encoded).
1217// Generate this with: cd apps/license-server && pnpm run generate-keys
1318// Then copy the public key here.
@@ -49,13 +54,20 @@ fn activate_license_internal(
4954 store. set ( STORE_KEY_SHORT_CODE , serde_json:: json!( code) ) ;
5055 }
5156
52- Ok ( LicenseInfo {
57+ let info = LicenseInfo {
5358 email : data. email ,
5459 transaction_id : data. transaction_id ,
5560 issued_at : data. issued_at ,
5661 organization_name : data. organization_name ,
5762 short_code : short_code. map ( |s| s. to_string ( ) ) ,
58- } )
63+ } ;
64+
65+ // Update the in-memory cache with the newly activated license
66+ if let Ok ( mut cache) = LICENSE_CACHE . lock ( ) {
67+ * cache = Some ( info. clone ( ) ) ;
68+ }
69+
70+ Ok ( info)
5971}
6072
6173/// Activate a license key (full key, not short code). Returns the license info if valid.
@@ -79,21 +91,43 @@ pub async fn activate_license_async(app: &tauri::AppHandle, input: &str) -> Resu
7991 activate_license_internal ( app, & full_key, short_code)
8092}
8193
82- /// Get stored license info, if any.
94+ /// Get stored license info, if any. Returns a cached result after the first successful verification.
8395pub fn get_license_info ( app : & tauri:: AppHandle ) -> Option < LicenseInfo > {
96+ // Fast path: return cached info if available
97+ if let Ok ( cache) = LICENSE_CACHE . lock ( )
98+ && let Some ( ref info) = * cache
99+ {
100+ return Some ( info. clone ( ) ) ;
101+ }
102+
103+ // Slow path: read from store and verify Ed25519 signature
84104 let store = app. store ( "license.json" ) . ok ( ) ?;
85105 let license_key = store. get ( STORE_KEY_LICENSE ) ?. as_str ( ) ?. to_string ( ) ;
86106 let short_code = store
87107 . get ( STORE_KEY_SHORT_CODE )
88108 . and_then ( |v| v. as_str ( ) . map ( |s| s. to_string ( ) ) ) ;
89109
90- validate_license_key ( & license_key) . ok ( ) . map ( |data| LicenseInfo {
110+ let info = validate_license_key ( & license_key) . ok ( ) . map ( |data| LicenseInfo {
91111 email : data. email ,
92112 transaction_id : data. transaction_id ,
93113 issued_at : data. issued_at ,
94114 organization_name : data. organization_name ,
95115 short_code,
96- } )
116+ } ) ?;
117+
118+ // Populate cache for subsequent calls
119+ if let Ok ( mut cache) = LICENSE_CACHE . lock ( ) {
120+ * cache = Some ( info. clone ( ) ) ;
121+ }
122+
123+ Some ( info)
124+ }
125+
126+ /// Clear the in-memory license cache. Called when the license is reset.
127+ pub fn clear_license_cache ( ) {
128+ if let Ok ( mut cache) = LICENSE_CACHE . lock ( ) {
129+ * cache = None ;
130+ }
97131}
98132
99133/// Validate a license key and extract the data.
0 commit comments