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}