binaryninja/repository/
plugin.rs

1use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
2use crate::repository::{PluginStatus, PluginType};
3use crate::string::BnString;
4use crate::VersionInfo;
5use binaryninjacore_sys::*;
6use std::ffi::c_char;
7use std::fmt::Debug;
8use std::path::PathBuf;
9use std::ptr::NonNull;
10use std::time::{Duration, SystemTime, UNIX_EPOCH};
11
12#[repr(transparent)]
13pub struct RepositoryPlugin {
14    handle: NonNull<BNRepoPlugin>,
15}
16
17impl RepositoryPlugin {
18    pub(crate) unsafe fn from_raw(handle: NonNull<BNRepoPlugin>) -> Self {
19        Self { handle }
20    }
21
22    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNRepoPlugin>) -> Ref<Self> {
23        Ref::new(Self { handle })
24    }
25
26    /// String indicating the API used by the plugin
27    pub fn apis(&self) -> Array<BnString> {
28        let mut count = 0;
29        let result = unsafe { BNPluginGetApis(self.handle.as_ptr(), &mut count) };
30        assert!(!result.is_null());
31        unsafe { Array::new(result, count, ()) }
32    }
33
34    /// String of the plugin author
35    pub fn author(&self) -> String {
36        let result = unsafe { BNPluginGetAuthor(self.handle.as_ptr()) };
37        assert!(!result.is_null());
38        unsafe { BnString::into_string(result as *mut c_char) }
39    }
40
41    /// String short description of the plugin
42    pub fn description(&self) -> String {
43        let result = unsafe { BNPluginGetDescription(self.handle.as_ptr()) };
44        assert!(!result.is_null());
45        unsafe { BnString::into_string(result as *mut c_char) }
46    }
47
48    /// String complete license text for the given plugin
49    pub fn license_text(&self) -> String {
50        let result = unsafe { BNPluginGetLicenseText(self.handle.as_ptr()) };
51        assert!(!result.is_null());
52        unsafe { BnString::into_string(result as *mut c_char) }
53    }
54
55    /// String long description of the plugin
56    pub fn long_description(&self) -> String {
57        let result = unsafe { BNPluginGetLongdescription(self.handle.as_ptr()) };
58        assert!(!result.is_null());
59        unsafe { BnString::into_string(result as *mut c_char) }
60    }
61
62    /// Minimum version info the plugin was tested on
63    pub fn minimum_version_info(&self) -> VersionInfo {
64        let result = unsafe { BNPluginGetMinimumVersionInfo(self.handle.as_ptr()) };
65        VersionInfo::from_owned_raw(result)
66    }
67
68    /// Maximum version info the plugin will support
69    pub fn maximum_version_info(&self) -> VersionInfo {
70        let result = unsafe { BNPluginGetMaximumVersionInfo(self.handle.as_ptr()) };
71        VersionInfo::from_owned_raw(result)
72    }
73
74    /// String plugin name
75    pub fn name(&self) -> String {
76        let result = unsafe { BNPluginGetName(self.handle.as_ptr()) };
77        assert!(!result.is_null());
78        unsafe { BnString::into_string(result as *mut c_char) }
79    }
80
81    /// String URL of the plugin's git repository
82    pub fn project_url(&self) -> String {
83        let result = unsafe { BNPluginGetProjectUrl(self.handle.as_ptr()) };
84        assert!(!result.is_null());
85        unsafe { BnString::into_string(result as *mut c_char) }
86    }
87
88    /// String URL of the plugin's git repository
89    pub fn package_url(&self) -> String {
90        let result = unsafe { BNPluginGetPackageUrl(self.handle.as_ptr()) };
91        assert!(!result.is_null());
92        unsafe { BnString::into_string(result as *mut c_char) }
93    }
94
95    /// String URL of the plugin author's url
96    pub fn author_url(&self) -> String {
97        let result = unsafe { BNPluginGetAuthorUrl(self.handle.as_ptr()) };
98        assert!(!result.is_null());
99        unsafe { BnString::into_string(result as *mut c_char) }
100    }
101    /// String version of the plugin
102    pub fn version(&self) -> String {
103        let result = unsafe { BNPluginGetVersion(self.handle.as_ptr()) };
104        assert!(!result.is_null());
105        unsafe { BnString::into_string(result as *mut c_char) }
106    }
107
108    /// String of the commit of this plugin git repository
109    pub fn commit(&self) -> String {
110        let result = unsafe { BNPluginGetCommit(self.handle.as_ptr()) };
111        assert!(!result.is_null());
112        unsafe { BnString::into_string(result as *mut c_char) }
113    }
114
115    /// Relative path from the base of the repository to the actual plugin
116    pub fn path(&self) -> PathBuf {
117        let result = unsafe { BNPluginGetPath(self.handle.as_ptr()) };
118        assert!(!result.is_null());
119        let result_str = unsafe { BnString::into_string(result as *mut c_char) };
120        PathBuf::from(result_str)
121    }
122
123    /// Optional sub-directory the plugin code lives in as a relative path from the plugin root
124    pub fn subdir(&self) -> PathBuf {
125        let result = unsafe { BNPluginGetSubdir(self.handle.as_ptr()) };
126        assert!(!result.is_null());
127        let result_str = unsafe { BnString::into_string(result as *mut c_char) };
128        PathBuf::from(result_str)
129    }
130
131    /// Dependencies required for installing this plugin
132    pub fn dependencies(&self) -> String {
133        let result = unsafe { BNPluginGetDependencies(self.handle.as_ptr()) };
134        assert!(!result.is_null());
135        unsafe { BnString::into_string(result as *mut c_char) }
136    }
137
138    /// true if the plugin is installed, false otherwise
139    pub fn is_installed(&self) -> bool {
140        unsafe { BNPluginIsInstalled(self.handle.as_ptr()) }
141    }
142
143    /// true if the plugin is enabled, false otherwise
144    pub fn is_enabled(&self) -> bool {
145        unsafe { BNPluginIsEnabled(self.handle.as_ptr()) }
146    }
147
148    pub fn status(&self) -> PluginStatus {
149        unsafe { BNPluginGetPluginStatus(self.handle.as_ptr()) }
150    }
151
152    /// List of PluginType enumeration objects indicating the plugin type(s)
153    pub fn types(&self) -> Array<PluginType> {
154        let mut count = 0;
155        let result = unsafe { BNPluginGetPluginTypes(self.handle.as_ptr(), &mut count) };
156        assert!(!result.is_null());
157        unsafe { Array::new(result, count, ()) }
158    }
159
160    /// Enable this plugin, optionally trying to force it.
161    /// Force loading a plugin with ignore platform and api constraints.
162    pub fn enable(&self, force: bool) -> bool {
163        unsafe { BNPluginEnable(self.handle.as_ptr(), force) }
164    }
165
166    pub fn disable(&self) -> bool {
167        unsafe { BNPluginDisable(self.handle.as_ptr()) }
168    }
169
170    /// Attempt to install the given plugin
171    pub fn install(&self) -> bool {
172        unsafe { BNPluginInstall(self.handle.as_ptr()) }
173    }
174
175    pub fn install_dependencies(&self) -> bool {
176        unsafe { BNPluginInstallDependencies(self.handle.as_ptr()) }
177    }
178
179    /// Attempt to uninstall the given plugin
180    pub fn uninstall(&self) -> bool {
181        unsafe { BNPluginUninstall(self.handle.as_ptr()) }
182    }
183
184    pub fn updated(&self) -> bool {
185        unsafe { BNPluginUpdate(self.handle.as_ptr()) }
186    }
187
188    /// List of platforms this plugin can execute on
189    pub fn platforms(&self) -> Array<BnString> {
190        let mut count = 0;
191        let result = unsafe { BNPluginGetPlatforms(self.handle.as_ptr(), &mut count) };
192        assert!(!result.is_null());
193        unsafe { Array::new(result, count, ()) }
194    }
195
196    pub fn repository(&self) -> String {
197        let result = unsafe { BNPluginGetRepository(self.handle.as_ptr()) };
198        assert!(!result.is_null());
199        unsafe { BnString::into_string(result as *mut c_char) }
200    }
201
202    /// Boolean status indicating that the plugin is being deleted
203    pub fn is_being_deleted(&self) -> bool {
204        unsafe { BNPluginIsBeingDeleted(self.handle.as_ptr()) }
205    }
206
207    /// Boolean status indicating that the plugin is being updated
208    pub fn is_being_updated(&self) -> bool {
209        unsafe { BNPluginIsBeingUpdated(self.handle.as_ptr()) }
210    }
211
212    /// Boolean status indicating that the plugin is currently running
213    pub fn is_running(&self) -> bool {
214        unsafe { BNPluginIsRunning(self.handle.as_ptr()) }
215    }
216
217    /// Boolean status indicating that the plugin has updates will be installed after the next restart
218    pub fn is_update_pending(&self) -> bool {
219        unsafe { BNPluginIsUpdatePending(self.handle.as_ptr()) }
220    }
221
222    /// Boolean status indicating that the plugin will be disabled after the next restart
223    pub fn is_disable_pending(&self) -> bool {
224        unsafe { BNPluginIsDisablePending(self.handle.as_ptr()) }
225    }
226
227    /// Boolean status indicating that the plugin will be deleted after the next restart
228    pub fn is_delete_pending(&self) -> bool {
229        unsafe { BNPluginIsDeletePending(self.handle.as_ptr()) }
230    }
231
232    /// Boolean status indicating that the plugin has updates available
233    pub fn is_updated_available(&self) -> bool {
234        unsafe { BNPluginIsUpdateAvailable(self.handle.as_ptr()) }
235    }
236
237    /// Boolean status indicating that the plugin's dependencies are currently being installed
238    pub fn are_dependencies_being_installed(&self) -> bool {
239        unsafe { BNPluginAreDependenciesBeingInstalled(self.handle.as_ptr()) }
240    }
241
242    /// Gets a json object of the project data field
243    pub fn project_data(&self) -> String {
244        let result = unsafe { BNPluginGetProjectData(self.handle.as_ptr()) };
245        assert!(!result.is_null());
246        unsafe { BnString::into_string(result) }
247    }
248
249    /// Returns a datetime object representing the plugins last update
250    pub fn last_update(&self) -> SystemTime {
251        let result = unsafe { BNPluginGetLastUpdate(self.handle.as_ptr()) };
252        UNIX_EPOCH + Duration::from_secs(result)
253    }
254}
255
256impl Debug for RepositoryPlugin {
257    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258        f.debug_struct("RepositoryPlugin")
259            .field("name", &self.name())
260            .field("version", &self.version())
261            .field("author", &self.author())
262            .field("description", &self.description())
263            .field("minimum_version_info", &self.minimum_version_info())
264            .field("maximum_version_info", &self.maximum_version_info())
265            .field("last_update", &self.last_update())
266            .field("status", &self.status())
267            .finish()
268    }
269}
270
271impl ToOwned for RepositoryPlugin {
272    type Owned = Ref<Self>;
273
274    fn to_owned(&self) -> Self::Owned {
275        unsafe { RefCountable::inc_ref(self) }
276    }
277}
278
279unsafe impl RefCountable for RepositoryPlugin {
280    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
281        Self::ref_from_raw(NonNull::new(BNNewPluginReference(handle.handle.as_ptr())).unwrap())
282    }
283
284    unsafe fn dec_ref(handle: &Self) {
285        BNFreePlugin(handle.handle.as_ptr())
286    }
287}
288
289impl CoreArrayProvider for RepositoryPlugin {
290    type Raw = *mut BNRepoPlugin;
291    type Context = ();
292    type Wrapped<'a> = Guard<'a, Self>;
293}
294
295unsafe impl CoreArrayProviderInner for RepositoryPlugin {
296    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
297        BNFreeRepositoryPluginList(raw)
298    }
299
300    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
301        Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context)
302    }
303}