twitter_archive/structs/
ip_audit.rs

1#!/usr/bin/env rust
2
3//! Tweeter archives as of 2023-08-31 have private data found under;
4//!
5//!   twitter-<DATE>-<UID>.zip:data/ip-audit.js
6//!
7//! ## Example file reader
8//!
9//! ```no_build
10//! use std::io::Read;
11//! use std::{fs, path};
12//! use zip::read::ZipArchive;
13//!
14//! use twitter_archive::structs::ip_audit;
15//!
16//! fn main() {
17//!     let input_file = "~/Downloads/twitter-archive.zip";
18//!
19//!     let file_descriptor = fs::File::open(input_file).expect("Unable to read --input-file");
20//!     let mut zip_archive = ZipArchive::new(file_descriptor).unwrap();
21//!     let mut zip_file = zip_archive.by_name("data/ip-audit.js").unwrap();
22//!     let mut buff = String::new();
23//!     zip_file.read_to_string(&mut buff).unwrap();
24//!
25//!     let json = buff.replacen("window.YTD.ip_audit.part0 = ", "", 1);
26//!     let data: Vec<ip_audit::IpAuditObject> = serde_json::from_str(&json).expect("Unable to parse");
27//!
28//!     for (index, object) in data.iter().enumerate() {
29//!         /* Do stuff with each `RegisteredDevices` entry */
30//!         println!("IP audit index: {index}");
31//!         println!("Account ID: {}", object.ip_audit.account_id);
32//!         println!("Created at: {}", object.ip_audit.created_at);
33//!         println!("Login IP: {}", object.ip_audit.login_ip);
34//!     }
35//! }
36//! ```
37//!
38//! ## Example `twitter-<DATE>-<UID>.zip:data/ip-audit.js` content
39//!
40//! ```javascript
41//! window.YTD.ip_audit.part0 = [
42//!   {
43//!     "ipAudit" : {
44//!       "accountId" : "111111111",
45//!       "createdAt" : "2023-05-30T13:31:42.908Z",
46//!       "loginIp" : "127.0.0.1"
47//!     }
48//!   },
49//!   {
50//!     "ipAudit" : {
51//!       "accountId" : "111111111",
52//!       "createdAt" : "2023-04-30T13:31:42.908Z",
53//!       "loginIp" : "127.0.0.1"
54//!     }
55//!   }
56//! ]
57//! ```
58
59use chrono::{DateTime, Utc};
60use derive_more::Display;
61use serde::{Deserialize, Serialize};
62
63use crate::convert;
64
65/// ## Example
66///
67/// ```
68/// use chrono::{DateTime, NaiveDateTime, Utc};
69///
70/// use twitter_archive::convert::date_time_iso_8601;
71///
72/// use twitter_archive::structs::ip_audit::IpAuditObject;
73///
74/// let created_at_string = "2023-05-30T13:31:42.908Z";
75/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
76/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
77///
78/// let json = format!(r#"{{
79///   "ipAudit": {{
80///     "accountId": "111111111",
81///     "createdAt": "{created_at_string}",
82///     "loginIp": "127.0.0.1"
83///   }}
84/// }}"#);
85///
86/// let data: IpAuditObject = serde_json::from_str(&json).unwrap();
87///
88/// // De-serialized properties
89/// assert_eq!(data.ip_audit.account_id, "111111111");
90/// assert_eq!(data.ip_audit.created_at, created_at_date_time);
91/// assert_eq!(data.ip_audit.login_ip, "127.0.0.1");
92///
93/// // Re-serialize is equivalent to original data
94/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
95/// ```
96#[derive(Deserialize, Serialize, Debug, Clone, Display)]
97#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
98#[serde(rename_all = "camelCase")]
99pub struct IpAuditObject {
100	/// ## Example JSON data
101	///
102	/// ```json
103	/// {
104	///   "ipAudit": {
105	///     "accountId": "111111111",
106	///     "createdAt": "2023-05-30T13:31:42.908Z",
107	///     "loginIp": "127.0.0.1"
108	///   }
109	/// }
110	/// ```
111	pub ip_audit: IpAudit,
112}
113
114/// ## Example
115///
116/// ```
117/// use chrono::{DateTime, NaiveDateTime, Utc};
118///
119/// use twitter_archive::convert::date_time_iso_8601;
120///
121/// use twitter_archive::structs::ip_audit::IpAudit;
122///
123/// let created_at_string = "2023-05-30T13:31:42.908Z";
124/// let created_at_native_time = NaiveDateTime::parse_from_str(&created_at_string, date_time_iso_8601::FORMAT).unwrap();
125/// let created_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(created_at_native_time, Utc);
126///
127/// let json = format!(r#"{{
128///   "accountId": "111111111",
129///   "createdAt": "{created_at_string}",
130///   "loginIp": "127.0.0.1"
131/// }}"#);
132///
133/// let data: IpAudit = serde_json::from_str(&json).unwrap();
134///
135/// // De-serialized properties
136/// assert_eq!(data.account_id, "111111111");
137/// assert_eq!(data.created_at, created_at_date_time);
138/// assert_eq!(data.login_ip, "127.0.0.1");
139///
140/// // Re-serialize is equivalent to original data
141/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
142/// ```
143#[derive(Deserialize, Serialize, Debug, Clone, Display)]
144#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
145#[serde(rename_all = "camelCase")]
146pub struct IpAudit {
147	/// ## Example JSON data
148	///
149	/// ```json
150	/// { "accountId": "111111111" }
151	/// ```
152	pub account_id: String,
153
154	/// ## Example JSON data
155	///
156	/// ```json
157	/// { "createdAt": "2023-05-30T13:31:42.908Z" }
158	/// ```
159	#[serde(with = "convert::date_time_iso_8601")]
160	pub created_at: DateTime<Utc>,
161
162	/// ## Example JSON data
163	///
164	/// ```json
165	/// { "loginIp": "127.0.0.1" }
166	/// ```
167	pub login_ip: String,
168}