@@ -4,6 +4,68 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
44use crate :: rc:: Array ;
55use crate :: string:: { BnStrCompatible , BnString } ;
66
7+
8+ #[ derive( Debug ) ]
9+ pub struct EnterpriseCheckoutError ( pub String ) ;
10+
11+ impl std:: fmt:: Display for EnterpriseCheckoutError {
12+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
13+ write ! ( f, "{}" , self . 0 )
14+ }
15+ }
16+
17+ impl std:: error:: Error for EnterpriseCheckoutError { }
18+
19+ pub fn checkout_license ( duration : Duration ) -> Result < ( ) , EnterpriseCheckoutError > {
20+ if crate :: is_ui_enabled ( ) {
21+ return Ok ( ( ) ) ;
22+ }
23+
24+ if !is_server_initialized ( ) {
25+ if !initialize_server ( ) && is_server_floating_license ( ) {
26+ return Err ( EnterpriseCheckoutError ( server_last_error ( ) . to_string ( ) ) ) ;
27+ }
28+ }
29+
30+ if is_server_floating_license ( ) {
31+ if !is_server_connected ( ) && !connect_server ( ) {
32+ return Err ( EnterpriseCheckoutError ( server_last_error ( ) . to_string ( ) ) ) ;
33+ }
34+
35+ if !is_server_authenticated ( ) {
36+ if !authenticate_server_with_method ( "Keychain" , false ) {
37+ let Some ( username) = std:: env:: var ( "BN_ENTERPRISE_USERNAME" ) . ok ( ) else {
38+ return Err ( EnterpriseCheckoutError ( "BN_ENTERPRISE_USERNAME not set when attempting to authenticate with credentials" . to_string ( ) ) ) ;
39+ } ;
40+ let Some ( password) = std:: env:: var ( "BN_ENTERPRISE_PASSWORD" ) . ok ( ) else {
41+ return Err ( EnterpriseCheckoutError ( "BN_ENTERPRISE_PASSWORD not set when attempting to authenticate with credentials" . to_string ( ) ) ) ;
42+ } ;
43+ if !authenticate_server_with_credentials ( username, password, true ) {
44+ let failed_message = "Could not checkout a license: Not authenticated. Try one of the following: \n \
45+ - Log in and check out a license for an extended time\n \
46+ - Set BN_ENTERPRISE_USERNAME and BN_ENTERPRISE_PASSWORD environment variables\n \
47+ - Use binaryninja::enterprise::{authenticate_server_with_method OR authenticate_server_with_credentials} in your code";
48+ return Err ( EnterpriseCheckoutError ( failed_message. to_string ( ) ) ) ;
49+ }
50+ }
51+ }
52+ }
53+
54+ if !is_server_license_still_activated ( ) || ( !is_server_floating_license ( ) && crate :: license_expiration_time ( ) < SystemTime :: now ( ) ) {
55+ if !update_server_license ( duration) {
56+ return Err ( EnterpriseCheckoutError ( "Failed to refresh expired license" . to_string ( ) ) ) ;
57+ }
58+ }
59+
60+ Ok ( ( ) )
61+ }
62+
63+ pub fn release_license ( ) {
64+ if !crate :: is_ui_enabled ( ) {
65+ release_server_license ( ) ;
66+ }
67+ }
68+
769pub fn server_username ( ) -> BnString {
870 unsafe { BnString :: from_raw ( binaryninjacore_sys:: BNGetEnterpriseServerUsername ( ) ) }
971}
@@ -125,6 +187,10 @@ pub fn is_server_initialized() -> bool {
125187 unsafe { binaryninjacore_sys:: BNIsEnterpriseServerInitialized ( ) }
126188}
127189
190+ pub fn initialize_server ( ) -> bool {
191+ unsafe { binaryninjacore_sys:: BNInitializeEnterpriseServer ( ) }
192+ }
193+
128194pub fn server_last_error ( ) -> BnString {
129195 unsafe { BnString :: from_raw ( binaryninjacore_sys:: BNGetEnterpriseServerLastError ( ) ) }
130196}
0 commit comments