1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
use crate::{
    types::{AcrDriver, ScanFrequency, Source},
    Error, HttpRequest, Response, Tenable,
};
use http::{header::HeaderValue, status::StatusCode, Method, Request};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, fmt};

/// Request Object for the `asset_by_uuid` function
#[derive(Clone, Debug)]
pub struct AssetByUuidReq<'a> {
    /// Inner tenable Client
    pub tenable: &'a Tenable<'a>,
    /// UUID which identifies the asset
    pub asset_uuid: Cow<'a, str>,
}

impl<RE: fmt::Debug> HttpRequest<RE> for AssetByUuidReq<'_> {
    type Output = Option<AssetByUuid>;

    #[inline]
    fn to_request(&self) -> Result<Request<Vec<u8>>, Error<RE>> {
        let req = Request::builder()
            .uri(format!(
                "{}/assets/{asset_uuid}",
                self.tenable.uri,
                asset_uuid = self.asset_uuid
            ))
            .method(Method::GET)
            .header(
                "X-ApiKeys",
                HeaderValue::from_str(self.tenable.auth.as_ref())?,
            )
            .header("Accept", HeaderValue::from_static("application/json"))
            .body(Vec::new())?;
        Ok(req)
    }

    #[inline]
    fn from_response(&self, res: Response) -> Result<Self::Output, Error<RE>> {
        match res.status {
            StatusCode::OK => {}
            StatusCode::FORBIDDEN => return Err(Error::InsufficientPermission),
            StatusCode::TOO_MANY_REQUESTS => return Err(Error::RateLimitReached),
            StatusCode::NOT_FOUND => return Ok(None),
            code => return Err(Error::UnexpectedStatusCode(code)),
        }
        let data = serde_json::from_slice(&res.body)?;
        Ok(Some(data))
    }
}

impl<'a> From<AssetByUuidReq<'a>> for Cow<'a, AssetByUuidReq<'a>> {
    #[inline]
    fn from(req: AssetByUuidReq<'a>) -> Self {
        Cow::Owned(req)
    }
}

impl<'a> From<&'a AssetByUuidReq<'a>> for Cow<'a, AssetByUuidReq<'a>> {
    #[inline]
    fn from(req: &'a AssetByUuidReq<'a>) -> Self {
        Cow::Borrowed(req)
    }
}

/// Represents the `Asset` returned by `asset_by_uuid`
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct AssetByUuid {
    /// The UUID of the asset. Use this value as the unique key for the asset.
    #[serde(rename = "id", skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    /// A value specifying whether a Nessus agent scan detected the asset.
    #[serde(rename = "has_agent", skip_serializing_if = "Option::is_none")]
    pub has_agent: Option<bool>,
    /// The time and date when Tenable.io created the asset record.
    #[serde(rename = "created_at", skip_serializing_if = "Option::is_none")]
    pub created_at: Option<String>,
    /// The time and date when the asset record was last updated.
    #[serde(rename = "updated_at", skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<String>,
    /// The time and date when a scan first identified the asset.
    #[serde(rename = "first_seen", skip_serializing_if = "Option::is_none")]
    pub first_seen: Option<String>,
    /// The time and date of the scan that most recently identified the asset.
    #[serde(rename = "last_seen", skip_serializing_if = "Option::is_none")]
    pub last_seen: Option<String>,
    /// The IPv4 address, IPv6 address, or FQDN that the scanner last used to evaluate the asset.
    #[serde(rename = "last_scan_target", skip_serializing_if = "Option::is_none")]
    pub last_scan_target: Option<String>,
    /// The time and date of the last credentialed scan run on the asset.
    #[serde(
        rename = "last_authenticated_scan_date",
        skip_serializing_if = "Option::is_none"
    )]
    pub last_authenticated_scan_date: Option<String>,
    /// The time and date of the last scan that identified the asset as licensed. Tenable.io categorizes an asset as licensed if a scan of that asset has returned results from a non-discovery plugin within the last 90 days.
    #[serde(
        rename = "last_licensed_scan_date",
        skip_serializing_if = "Option::is_none"
    )]
    pub last_licensed_scan_date: Option<String>,
    /// The sources of the scans that identified the asset.
    #[serde(rename = "sources", skip_serializing_if = "Option::is_none")]
    pub sources: Option<Vec<Source>>,
    /// Category tags assigned to the asset in Tenable.io.
    #[serde(rename = "tags", skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<Tags>>,
    /// The Asset Criticality Rating (ACR) for the asset. Tenable assigns an ACR to each asset on your network to represent the asset's relative risk as an integer from 1 to 10. For more information, see [Lumin Metrics](https://docs.tenable.com/tenableio/vulnerabilitymanagement/Content/Analysis/LuminMetrics.htm) in the *Tenable.io Vulnerability Management User Guide*.  This attribute is only present if you have a Lumin license.
    #[serde(rename = "acr_score", skip_serializing_if = "Option::is_none")]
    pub acr_score: Option<i32>,
    /// The key drivers that Tenable uses to calculate an asset's Tenable-provided ACR. For more information, see [Lumin Metrics](https://docs.tenable.com/tenableio/vulnerabilitymanagement/Content/Analysis/LuminMetrics.htm) in the *Tenable.io Vulnerability Management User Guide*.  This attribute is only present if you have a Lumin license.
    #[serde(rename = "acr_drivers", skip_serializing_if = "Option::is_none")]
    pub acr_drivers: Option<Vec<AcrDriver>>,
    /// The Asset Exposure Score (AES) for the asset. For more information, see [Lumin Metrics](https://docs.tenable.com/tenableio/vulnerabilitymanagement/Content/Analysis/LuminMetrics.htm) in the *Tenable.io Vulnerability Management User Guide*.
    #[serde(rename = "exposure_score", skip_serializing_if = "Option::is_none")]
    pub exposure_score: Option<i32>,
    /// Information about how often scans ran against the asset during specified intervals.
    #[serde(rename = "scan_frequency", skip_serializing_if = "Option::is_none")]
    pub scan_frequency: Option<Vec<ScanFrequency>>,
    /// The ID of the network object to which the asset belongs. For more information, see [Manage Networks](doc:manage-networks-tio).
    #[serde(rename = "network_id", skip_serializing_if = "Option::is_none")]
    pub network_id: Option<Vec<String>>,
    /// The IPv4 addresses that scans have associated with the asset record.
    #[serde(rename = "ipv4", skip_serializing_if = "Option::is_none")]
    pub ipv4: Option<Vec<String>>,
    /// The IPv6 addresses that scans have associated with the asset record.
    #[serde(rename = "ipv6", skip_serializing_if = "Option::is_none")]
    pub ipv6: Option<Vec<String>>,
    /// The fully-qualified domain names that scans have associated with the asset record.
    #[serde(rename = "fqdn", skip_serializing_if = "Option::is_none")]
    pub fqdn: Option<Vec<String>>,
    /// The MAC addresses that scans have associated with the asset record.
    #[serde(rename = "mac_address", skip_serializing_if = "Option::is_none")]
    pub mac_address: Option<Vec<String>>,
    /// The NetBIOS names that scans have associated with the asset record.
    #[serde(rename = "netbios_name", skip_serializing_if = "Option::is_none")]
    pub netbios_name: Option<Vec<String>>,
    /// The operating systems that scans have associated with the asset record.
    #[serde(rename = "operating_system", skip_serializing_if = "Option::is_none")]
    pub operating_system: Option<Vec<String>>,
    /// The system types as reported by Plugin ID 54615. Possible values include `router`, `general-purpose`, `scan-host`, and `embedded`.
    #[serde(rename = "system_type", skip_serializing_if = "Option::is_none")]
    pub system_type: Option<Vec<String>>,
    /// The UUID of the agent present on the asset. This attribute is empty if no agent is present on the asset.
    #[serde(rename = "tenable_uuid", skip_serializing_if = "Option::is_none")]
    pub tenable_uuid: Option<Vec<String>>,
    /// The hostnames that scans have associated with the asset record.
    #[serde(rename = "hostname", skip_serializing_if = "Option::is_none")]
    pub hostname: Option<Vec<String>>,
    /// The names of any Nessus agents that scanned and identified the asset.
    #[serde(rename = "agent_name", skip_serializing_if = "Option::is_none")]
    pub agent_name: Option<Vec<String>>,
    /// The BIOS UUID that scans have associated with the asset.
    #[serde(rename = "bios_uuid", skip_serializing_if = "Option::is_none")]
    pub bios_uuid: Option<Vec<String>>,
    /// The unique identifier of the Linux instance in Amazon EC2. For more information, see the Amazon Elastic Compute Cloud Documentation.
    #[serde(
        rename = "aws_ec2_instance_id",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_instance_id: Option<Vec<String>>,
    /// The unique identifier of the Linux AMI image in Amazon Elastic Compute Cloud (Amazon EC2). For more information, see the Amazon Elastic Compute Cloud Documentation.
    #[serde(
        rename = "aws_ec2_instance_ami_id",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_instance_ami_id: Option<Vec<String>>,
    /// The canonical user identifier for the AWS account associated with the virtual machine instance. For example, `79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be`. For more information, see AWS Account Identifiers in the AWS documentation.
    #[serde(rename = "aws_owner_id", skip_serializing_if = "Option::is_none")]
    pub aws_owner_id: Option<Vec<String>>,
    /// The availability zone where Amazon Web Services hosts the virtual machine instance, for example, `us-east-1a`. Availability zones are subdivisions of AWS regions. For more information, see Regions and Availability Zones in the AWS documentation.
    #[serde(
        rename = "aws_availability_zone",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_availability_zone: Option<Vec<String>>,
    /// The region where AWS hosts the virtual machine instance, for example, `us-east-1`. For more information, see Regions and Availability Zones in the AWS documentation.
    #[serde(rename = "aws_region", skip_serializing_if = "Option::is_none")]
    pub aws_region: Option<Vec<String>>,
    /// The unique identifier for the public cloud that hosts the AWS virtual machine instance. For more information, see the Amazon Virtual Private Cloud User Guide.
    #[serde(rename = "aws_vpc_id", skip_serializing_if = "Option::is_none")]
    pub aws_vpc_id: Option<Vec<String>>,
    /// The virtual machine instance's group in AWS.
    #[serde(
        rename = "aws_ec2_instance_group_name",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_instance_group_name: Option<Vec<String>>,
    /// The state of the virtual machine instance in AWS at the time of the scan. For more information on instance states, see the AWS documentation.
    #[serde(
        rename = "aws_ec2_instance_state_name",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_instance_state_name: Option<Vec<String>>,
    /// The type of instance in AWS EC2.
    #[serde(
        rename = "aws_ec2_instance_type",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_instance_type: Option<Vec<String>>,
    /// The unique identifier of the AWS subnet where the virtual machine instance was running at the time of the scan.
    #[serde(rename = "aws_subnet_id", skip_serializing_if = "Option::is_none")]
    pub aws_subnet_id: Option<Vec<String>>,
    /// The product code associated with the AMI used to launch the virtual machine instance in AWS EC2.
    #[serde(
        rename = "aws_ec2_product_code",
        skip_serializing_if = "Option::is_none"
    )]
    pub aws_ec2_product_code: Option<Vec<String>>,
    /// The name of the virtual machine instance in AWS EC2.
    #[serde(rename = "aws_ec2_name", skip_serializing_if = "Option::is_none")]
    pub aws_ec2_name: Option<Vec<String>>,
    /// The unique identifier of the Microsoft Azure virtual machine instance. For more information, see \"Accessing and Using Azure VM Unique ID\" in the Microsoft Azure documentation.
    #[serde(rename = "azure_vm_id", skip_serializing_if = "Option::is_none")]
    pub azure_vm_id: Option<Vec<String>>,
    /// The unique identifier of the resource in the Azure Resource Manager. For more information, see the Azure Resource Manager Documentation.
    #[serde(rename = "azure_resource_id", skip_serializing_if = "Option::is_none")]
    pub azure_resource_id: Option<Vec<String>>,
    /// The customized name of the project to which the virtual machine instance belongs in Google Cloud Platform (GCP). For more information, see \"Creating and Managing Projects\" in the GCP documentation.
    #[serde(rename = "gcp_project_id", skip_serializing_if = "Option::is_none")]
    pub gcp_project_id: Option<Vec<String>>,
    /// The zone where the virtual machine instance runs in GCP. For more information, see \"Regions and Zones\" in the GCP documentation.
    #[serde(rename = "gcp_zone", skip_serializing_if = "Option::is_none")]
    pub gcp_zone: Option<Vec<String>>,
    /// The unique identifier of the virtual machine instance in GCP.
    #[serde(rename = "gcp_instance_id", skip_serializing_if = "Option::is_none")]
    pub gcp_instance_id: Option<Vec<String>>,
    /// The SSH key fingerprints that scans have associated with the asset record.
    #[serde(rename = "ssh_fingerprint", skip_serializing_if = "Option::is_none")]
    pub ssh_fingerprint: Option<Vec<String>>,
    /// The unique identifier of the asset in McAfee ePolicy Orchestrator (ePO). For more information, see the McAfee documentation.
    #[serde(rename = "mcafee_epo_guid", skip_serializing_if = "Option::is_none")]
    pub mcafee_epo_guid: Option<Vec<String>>,
    /// The unique identifier of the McAfee ePO agent that identified the asset. For more information, see the McAfee documentation.
    #[serde(
        rename = "mcafee_epo_agent_guid",
        skip_serializing_if = "Option::is_none"
    )]
    pub mcafee_epo_agent_guid: Option<Vec<String>>,
    /// The Asset ID of the asset in Qualys. For more information, see the Qualys documentation.
    #[serde(rename = "qualys_asset_id", skip_serializing_if = "Option::is_none")]
    pub qualys_asset_id: Option<Vec<String>>,
    /// The Host ID of the asset in Qualys. For more information, see the Qualys documentation.
    #[serde(rename = "qualys_host_id", skip_serializing_if = "Option::is_none")]
    pub qualys_host_id: Option<Vec<String>>,
    /// The unique record identifier of the asset in ServiceNow. For more information, see the ServiceNow documentation.
    #[serde(rename = "servicenow_sysid", skip_serializing_if = "Option::is_none")]
    pub servicenow_sysid: Option<Vec<String>>,
    /// A list of Common Platform Enumeration (CPE) values that represent software applications a scan identified as present on an asset. This attribute supports the CPE 2.2 format. For more information, see the \"Component Syntax\" section of the [CPE Specification, Version 2.2](https://cpe.mitre.org/files/cpe-specification_2.2.pdf). For assets identified in Tenable scans, this attribute contains data only if a scan using [Nessus Plugin ID 45590](https://www.tenable.com/plugins/nessus/45590) has evaluated the asset.  **Note:** If no scan detects an application within 30 days of the scan that originally detected the application, Tenable.io considers the detection of that application expired. As a result, the next time a scan evaluates the asset, Tenable.io removes the expired application from the installed_software attribute. This activity is logged as a `remove` type of `attribute_change` update in the asset activity log.
    #[serde(rename = "installed_software", skip_serializing_if = "Option::is_none")]
    pub installed_software: Option<Vec<String>>,
}

/// `Tags` blueprint
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Tags {
    /// The UUID of the tag.
    #[serde(rename = "tag_uuid", skip_serializing_if = "Option::is_none")]
    pub tag_uuid: Option<String>,
    /// The tag category (the first half of the category:value pair).
    #[serde(rename = "tag_key", skip_serializing_if = "Option::is_none")]
    pub tag_key: Option<String>,
    /// The tag value (the second half of the category:value pair).
    #[serde(rename = "tag_value", skip_serializing_if = "Option::is_none")]
    pub tag_value: Option<String>,
    /// The UUID of the user who assigned the tag to the asset.
    #[serde(rename = "added_by", skip_serializing_if = "Option::is_none")]
    pub added_by: Option<String>,
    /// The ISO timestamp when the tag was assigned to the asset.
    #[serde(rename = "added_at", skip_serializing_if = "Option::is_none")]
    pub added_at: Option<String>,
}