1use chrono::{DateTime, FixedOffset, Offset, TimeZone, Utc};
2use serde::de::{IntoDeserializer, SeqAccess, Unexpected, Visitor};
3use serde::ser::SerializeSeq;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::convert::TryFrom;
6use std::fmt;
7use std::fmt::Write;
8use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
9use std::slice::Iter;
10use std::str::FromStr;
11
12fn deserialize_string_lowercase<'de, D>(deserializer: D) -> Result<String, D::Error>
13where
14 D: Deserializer<'de>,
15{
16 let mut string = String::deserialize(deserializer)?;
17 if string.chars().any(|c| c.is_uppercase()) {
20 string = string.to_lowercase();
21 }
22 Ok(string)
23}
24
25fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
33where
34 D: Deserializer<'de>,
35{
36 let string = String::deserialize(deserializer)?;
37
38 DateTime::parse_from_rfc3339(&string)
39 .or_else(|_| {
40 if string.contains('T') {
41 Utc.datetime_from_str(&string, "%Y-%m-%dT%H:%M:%S")
42 .map(|d| d.with_timezone(&Utc.fix()))
43 .or_else(|_| DateTime::parse_from_str(&string, "%Y-%m-%dT%H:%M:%SZ%z"))
44 } else {
45 Utc.datetime_from_str(&string, "%Y-%m-%d %H:%M:%S")
46 .map(|d| d.with_timezone(&Utc.fix())) }
48 })
49 .map_err(serde::de::Error::custom)
50}
51
52#[derive(PartialEq)]
56pub struct CountryCode([u8; 2]);
57
58impl FromStr for CountryCode {
59 type Err = &'static str;
60
61 fn from_str(string: &str) -> Result<Self, Self::Err> {
62 let bytes = string.as_bytes();
63 if !bytes.is_ascii() || bytes.len() != 2 {
64 return Err("string is not two letter ascii");
65 }
66 Ok(Self([
67 bytes[0].to_ascii_uppercase(),
68 bytes[1].to_ascii_uppercase(),
69 ]))
70 }
71}
72
73impl fmt::Debug for CountryCode {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
75 write!(f, "{}", self)
76 }
77}
78
79impl fmt::Display for CountryCode {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
81 f.write_char(self.0[0] as char)?;
82 f.write_char(self.0[1] as char)
83 }
84}
85
86impl Serialize for CountryCode {
87 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
88 where
89 S: Serializer,
90 {
91 let string = std::str::from_utf8(&self.0).unwrap(); serializer.serialize_str(string)
93 }
94}
95
96impl<'de> Deserialize<'de> for CountryCode {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: Deserializer<'de>,
100 {
101 struct CountryCodeVisitor;
102
103 impl<'de> Visitor<'de> for CountryCodeVisitor {
104 type Value = CountryCode;
105
106 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(formatter, "expecting a two letters country code")
108 }
109
110 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
111 where
112 E: serde::de::Error,
113 {
114 CountryCode::from_str(v).map_err(|_| {
115 serde::de::Error::invalid_value(serde::de::Unexpected::Str(v), &self)
116 })
117 }
118 }
119
120 deserializer.deserialize_str(CountryCodeVisitor)
121 }
122}
123
124#[derive(Serialize, Deserialize, Debug)]
126pub struct Link {
127 pub value: Option<String>,
128 pub rel: Option<String>,
129 pub href: String,
130 pub hreflang: Option<Vec<String>>,
131 pub title: Option<String>,
132 pub media: Option<String>,
133 #[serde(rename = "type")]
134 pub typ: Option<String>,
135}
136
137#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
143#[serde(rename_all = "lowercase")]
144#[serde(remote = "Role")]
145pub enum Role {
146 Registrant,
148 Technical,
150 Administrative,
152 Abuse,
154 Billing,
156 Registrar,
158 Reseller,
160 Sponsor,
162 Proxy,
164 Notifications,
166 Noc,
168 Routing,
170 Dns,
172 Zone,
174}
175
176impl<'de> Deserialize<'de> for Role {
177 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
178 where
179 D: Deserializer<'de>,
180 {
181 let s = deserialize_string_lowercase(deserializer)?;
182
183 match s.as_str() {
185 "tech" => Ok(Self::Technical),
186 "admin" => Ok(Self::Administrative),
187 _ => Self::deserialize(s.into_deserializer()),
188 }
189 }
190}
191
192impl Serialize for Role {
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: Serializer,
196 {
197 Self::serialize(self, serializer)
198 }
199}
200
201#[derive(Serialize, Deserialize, Debug)]
203pub struct PublicId {
204 #[serde(rename = "type")]
205 pub typ: String,
206 pub identifier: String,
207}
208
209#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
210#[serde(rename_all = "lowercase")]
211pub enum JCardType {
212 Vcard,
213}
214
215#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
217#[serde(rename_all = "kebab-case")]
218#[serde(remote = "JCardItemDataType")]
219pub enum JCardItemDataType {
220 Text,
221 TextList,
222 DateList,
223 TimeList,
224 DateTimeList,
225 DateAndOrTimeList,
226 TimestampList,
227 Boolean,
228 IntegerList,
229 FloatList,
230 Uri,
231 UtcOffset,
232 LanguageTag,
233 IanaValuespec,
234 Unknown,
236}
237
238impl<'de> Deserialize<'de> for JCardItemDataType {
239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240 where
241 D: Deserializer<'de>,
242 {
243 let s = deserialize_string_lowercase(deserializer)?;
244 Self::deserialize(s.into_deserializer())
245 }
246}
247
248impl Serialize for JCardItemDataType {
249 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
250 where
251 S: Serializer,
252 {
253 Self::serialize(self, serializer)
254 }
255}
256
257#[derive(Debug)]
258pub struct JCardItem {
259 pub property_name: String,
260 pub parameters: serde_json::Map<String, serde_json::Value>,
261 pub type_identifier: JCardItemDataType,
262 pub values: Vec<serde_json::Value>,
263}
264
265impl<'de> Deserialize<'de> for JCardItem {
266 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
267 where
268 D: Deserializer<'de>,
269 {
270 struct JCardItemVisitor;
271
272 impl<'de> Visitor<'de> for JCardItemVisitor {
273 type Value = JCardItem;
274
275 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
276 formatter.write_str("a sequence")
277 }
278
279 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
280 where
281 A: SeqAccess<'de>,
282 {
283 let invalid_length =
284 |size| serde::de::Error::invalid_length(size, &"at least four elements");
285
286 let mut property_name: String =
288 seq.next_element()?.ok_or_else(|| invalid_length(0))?;
289 if property_name.chars().any(|c| c.is_uppercase()) {
290 property_name = property_name.to_lowercase();
291 }
292
293 let parameters = seq.next_element()?.ok_or_else(|| invalid_length(1))?;
294 let type_identifier = seq.next_element()?.ok_or_else(|| invalid_length(2))?;
295
296 let mut values = vec![];
297 while let Some(value) = seq.next_element()? {
298 values.push(value);
299 }
300
301 if values.is_empty() {
302 return Err(invalid_length(3));
303 }
304
305 Ok(JCardItem {
306 property_name,
307 parameters,
308 type_identifier,
309 values,
310 })
311 }
312 }
313
314 deserializer.deserialize_seq(JCardItemVisitor)
315 }
316}
317
318impl Serialize for JCardItem {
319 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
320 where
321 S: Serializer,
322 {
323 let mut seq = serializer.serialize_seq(Some(3 + self.values.len()))?;
324 seq.serialize_element(&self.property_name)?;
325 seq.serialize_element(&self.parameters)?;
326 seq.serialize_element(&self.type_identifier)?;
327 for value in &self.values {
328 seq.serialize_element(value)?;
329 }
330 seq.end()
331 }
332}
333
334#[derive(Serialize, Deserialize, Debug)]
336pub struct JCard(JCardType, Vec<JCardItem>);
337
338impl JCard {
339 pub fn typ(&self) -> JCardType {
340 self.0
341 }
342
343 pub fn items(&self) -> &Vec<JCardItem> {
344 &self.1
345 }
346
347 pub fn items_by_name(&self, name: &str) -> Vec<&JCardItem> {
349 self.1.iter().filter(|p| p.property_name == name).collect()
350 }
351}
352
353#[derive(Serialize, Deserialize, Debug)]
354#[serde(rename_all = "camelCase")]
355pub struct Entity {
356 pub handle: Option<String>,
357 pub vcard_array: Option<JCard>,
358 pub roles: Option<Vec<Role>>,
359 pub public_ids: Option<Vec<PublicId>>,
360 pub entities: Option<Vec<Entity>>,
361 pub remarks: Option<NoticesOrRemarks>,
362 pub links: Option<Vec<Link>>,
363 pub events: Option<Events>,
364 pub as_event_actor: Option<Events>,
365 pub status: Option<Vec<Status>>,
366 pub port43: Option<String>,
367 pub lang: Option<String>,
368 pub object_class_name: String,
369}
370
371#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
373#[serde(rename_all = "lowercase")]
374pub enum Status {
375 Validated,
376 #[serde(rename = "renew prohibited")]
377 RenewProhibited,
378 #[serde(rename = "update prohibited")]
379 UpdateProhibited,
380 #[serde(rename = "transfer prohibited")]
381 TransferProhibited,
382 #[serde(rename = "delete prohibited")]
383 DeleteProhibited,
384 Proxy,
385 Private,
386 Removed,
387 Obscured,
388 Associated,
389 Active,
390 Inactive,
391 Locked,
392 #[serde(rename = "pending create")]
393 PendingCreate,
394 #[serde(rename = "pending renew")]
395 PendingRenew,
396 #[serde(rename = "pending transfer")]
397 PendingTransfer,
398 #[serde(rename = "pending update")]
399 PendingUpdate,
400 #[serde(rename = "pending delete")]
401 PendingDelete,
402 #[serde(rename = "add period")]
404 AddPeriod,
405 #[serde(rename = "auto renew period")]
406 AutoRenewPeriod,
407 #[serde(rename = "client delete prohibited")]
408 ClientDeleteProhibited,
409 #[serde(rename = "client hold")]
410 ClientHold,
411 #[serde(rename = "client renew prohibited")]
412 ClientRenewProhibited,
413 #[serde(rename = "client transfer prohibited")]
414 ClientTransferProhibited,
415 #[serde(rename = "client update prohibited")]
416 ClientUpdateProhibited,
417 #[serde(rename = "pending restore")]
418 PendingRestore,
419 #[serde(rename = "redemption period")]
420 RedemptionPeriod,
421 #[serde(rename = "renew period")]
422 RenewPeriod,
423 #[serde(rename = "server delete prohibited")]
424 ServerDeleteProhibited,
425 #[serde(rename = "server renew prohibited")]
426 ServerRenewProhibited,
427 #[serde(rename = "server transfer prohibited")]
428 ServerTransferProhibited,
429 #[serde(rename = "server update prohibited")]
430 ServerUpdateProhibited,
431 #[serde(rename = "server hold")]
432 ServerHold,
433 #[serde(rename = "transfer period")]
434 TransferPeriod,
435 Ok,
438}
439
440#[derive(Serialize, Deserialize, Debug)]
441pub struct IpAddresses {
442 pub v4: Option<Vec<Ipv4Addr>>,
443 pub v6: Option<Vec<Ipv6Addr>>,
444}
445
446#[derive(Serialize, Deserialize, Debug)]
448#[serde(rename_all = "camelCase")]
449pub struct Nameserver {
450 pub handle: Option<String>,
451 pub ldh_name: String,
452 pub unicode_name: Option<String>,
453 pub ip_addresses: Option<IpAddresses>,
454 pub entities: Option<Vec<Entity>>,
455 pub status: Option<Vec<Status>>,
456 pub remarks: Option<NoticesOrRemarks>,
457 pub notices: Option<NoticesOrRemarks>,
458 pub links: Option<Vec<Link>>,
459 pub object_class_name: String,
460}
461
462#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
464#[serde(rename_all = "lowercase")]
465#[serde(remote = "EventAction")]
466pub enum EventAction {
467 Registration,
468 Reregistration,
469 #[serde(rename = "last changed")]
470 LastChanged,
471 Expiration,
472 Deletion,
473 Reinstantiation,
474 Transfer,
475 Locked,
476 Unlocked,
477 #[serde(rename = "last update of RDAP database")]
479 LastUpdateOfRdapDatabase,
481 #[serde(rename = "registrar expiration")]
482 RegistrarExpiration,
484 #[serde(rename = "enum validation expiration")]
485 EnumValidationExpiration,
487 #[serde(rename = "delegation sign check")]
489 DelegationSignCheck,
491 #[serde(rename = "soft expiration")]
492 SoftExpiration,
494 #[serde(rename = "last correct delegation sign check")]
495 LastCorrectDelegationSignCheck,
497}
498
499impl<'de> Deserialize<'de> for EventAction {
500 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
501 where
502 D: Deserializer<'de>,
503 {
504 let s = deserialize_string_lowercase(deserializer)?;
505 if s == "last update of rdap database" {
506 Ok(Self::LastUpdateOfRdapDatabase)
509 } else {
510 Self::deserialize(s.into_deserializer())
511 }
512 }
513}
514
515impl Serialize for EventAction {
516 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
517 where
518 S: Serializer,
519 {
520 Self::serialize(self, serializer)
521 }
522}
523
524#[derive(Serialize, Deserialize, Debug)]
526#[serde(rename_all = "camelCase")]
527pub struct Event {
528 pub event_actor: Option<String>,
529 pub event_action: EventAction,
530 #[serde(deserialize_with = "deserialize_datetime")]
531 pub event_date: DateTime<FixedOffset>,
532 pub links: Option<Link>,
533}
534
535#[derive(Serialize, Deserialize, Debug)]
536pub struct Events(Vec<Event>);
537
538impl Events {
539 pub fn action_date(&self, action: EventAction) -> Option<DateTime<FixedOffset>> {
540 self.0
541 .iter()
542 .find(|p| p.event_action == action)
543 .map(|e| e.event_date)
544 }
545}
546
547impl<'a> IntoIterator for &'a Events {
548 type Item = &'a Event;
549 type IntoIter = Iter<'a, Event>;
550
551 fn into_iter(self) -> Self::IntoIter {
552 self.0.iter()
553 }
554}
555
556#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
558#[serde(remote = "NoticeOrRemarkType")]
559pub enum NoticeOrRemarkType {
560 #[serde(rename = "result set truncated due to authorization")]
561 ResultSetTruncatedDueToAuthorization,
562 #[serde(rename = "result set truncated due to excessive load")]
563 ResultSetTruncatedDueToExcessiveLoad,
564 #[serde(rename = "result set truncated due to unexplainable reasons")]
565 ResultSetTruncatedDueToUnexplainableReasons,
566 #[serde(rename = "object truncated due to authorization")]
567 ObjectTruncatedDueToAuthorization,
568 #[serde(rename = "object truncated due to excessive load")]
569 ObjectTruncatedDueToExcessiveLoad,
570 #[serde(rename = "object truncated due to unexplainable reasons")]
571 ObjectTruncatedDueToUnexplainableReasons,
572 #[serde(rename = "object redacted due to authorization")]
574 ObjectRedactedDueToAuthorization,
576 #[serde(rename = "object truncated due to server policy")]
578 ObjectTruncatedDueToServerPolicy,
579 #[serde(rename = "response truncated due to authorization")]
580 ResponseTruncatedDueToAuthorization,
582}
583
584impl<'de> Deserialize<'de> for NoticeOrRemarkType {
585 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
586 where
587 D: Deserializer<'de>,
588 {
589 let s = deserialize_string_lowercase(deserializer)?;
590 if s == "object redacted due to authorization." {
591 Ok(Self::ObjectRedactedDueToAuthorization)
593 } else {
594 Self::deserialize(s.into_deserializer())
595 }
596 }
597}
598
599impl Serialize for NoticeOrRemarkType {
600 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
601 where
602 S: Serializer,
603 {
604 Self::serialize(self, serializer)
605 }
606}
607
608#[derive(Serialize, Deserialize, Debug)]
609pub struct NoticeOrRemark {
610 pub title: Option<String>,
611 #[serde(rename = "type")]
612 pub typ: Option<NoticeOrRemarkType>,
613 pub description: Option<Vec<String>>,
614 pub links: Option<Vec<Link>>,
615}
616
617#[derive(Serialize, Deserialize, Debug)]
618pub struct NoticesOrRemarks(Vec<NoticeOrRemark>);
619
620impl NoticesOrRemarks {
621 pub fn description_by_title(&self, title: &str) -> Option<&Vec<String>> {
622 for remark in self.0.iter().filter(|p| p.description.is_some()) {
623 if let Some(t) = &remark.title {
624 if title.eq_ignore_ascii_case(t.as_str()) {
625 return remark.description.as_ref();
626 }
627 } else if title == "remarks" {
628 return remark.description.as_ref();
629 }
630 }
631
632 None
633 }
634}
635
636impl<'a> IntoIterator for &'a NoticesOrRemarks {
637 type Item = &'a NoticeOrRemark;
638 type IntoIter = Iter<'a, NoticeOrRemark>;
639
640 fn into_iter(self) -> Self::IntoIter {
641 self.0.iter()
642 }
643}
644
645#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
648#[serde(rename_all = "camelCase")]
649pub enum IpVersion {
650 V4,
651 V6,
652}
653
654#[derive(Serialize, Deserialize, Debug)]
656pub struct CidrOCidr {
657 pub v4prefix: Option<Ipv4Addr>,
658 pub v6prefix: Option<Ipv6Addr>,
659 pub length: u8,
660}
661
662#[derive(Serialize, Deserialize, Debug)]
663#[serde(rename_all = "camelCase")]
664pub struct IpNetwork {
665 pub handle: String,
666 pub start_address: IpAddr,
667 pub end_address: IpAddr,
668 pub ip_version: IpVersion,
669 pub name: Option<String>,
670 pub country: Option<CountryCode>,
671 pub parent_handle: Option<String>,
672 #[serde(rename = "type")]
673 pub typ: Option<String>,
674 pub entities: Option<Vec<Entity>>,
675 pub links: Option<Vec<Link>>,
676 pub remarks: Option<NoticesOrRemarks>,
677 pub events: Option<Events>,
678 pub rdap_conformance: Option<Vec<String>>,
679 pub notices: Option<NoticesOrRemarks>,
680 pub port43: Option<String>,
681 pub status: Option<Vec<Status>>,
682 pub lang: Option<String>,
683 pub object_class_name: String,
684 #[serde(rename = "cidr0_cidrs")]
686 pub cidr0_cidrs: Option<Vec<CidrOCidr>>,
687 #[serde(rename = "arin_originas0_originautnums")]
689 pub arin_originas0_originautnums: Option<Vec<u32>>,
690}
691
692#[derive(Serialize, Deserialize, Debug)]
694#[serde(rename_all = "camelCase")]
695pub struct AutNum {
696 pub handle: String,
697 pub start_autnum: Option<u32>,
698 pub end_autnum: Option<u32>,
699 pub name: Option<String>,
700 pub country: Option<CountryCode>,
701 #[serde(rename = "type")]
702 pub typ: Option<String>,
703 pub entities: Vec<Entity>,
704 pub links: Option<Vec<Link>>,
705 pub remarks: Option<NoticesOrRemarks>,
706 pub events: Option<Events>,
707 pub rdap_conformance: Option<Vec<String>>,
708 pub notices: Option<NoticesOrRemarks>,
709 pub port43: Option<String>,
710 pub status: Option<Vec<Status>>,
711 pub lang: Option<String>,
712 pub object_class_name: String,
713}
714
715#[derive(Serialize, Deserialize, Debug)]
717#[serde(rename_all = "lowercase")]
718enum DomainVariantRelation {
719 Registered,
720 Unregistered,
721 #[serde(rename = "registration restricted")]
722 RegistrationRestricted,
723 #[serde(rename = "open registration")]
724 OpenRegistration,
725 Conjoined,
726}
727
728#[derive(Serialize, Deserialize, Debug)]
729#[serde(rename_all = "camelCase")]
730pub struct VariantName {
731 ldh_name: String,
732 unicode_name: String,
733}
734
735#[derive(Serialize, Deserialize, Debug)]
736#[serde(rename_all = "camelCase")]
737pub struct Variant {
738 relation: Vec<DomainVariantRelation>,
739 idn_table: Option<String>,
740 variant_names: Vec<VariantName>,
741}
742
743#[derive(Serialize, Deserialize, Debug)]
745#[serde(rename_all = "camelCase")]
746pub struct DsData {
747 key_tag: Option<u16>,
748 algorithm: u8,
749 digest: String,
750 digest_type: u8,
751 events: Option<Events>,
752 links: Option<Vec<Link>>,
753}
754
755#[derive(Serialize, Deserialize, Debug)]
757#[serde(rename_all = "camelCase")]
758pub struct KeyData {
759 flags: u16,
760 protocol: u8,
761 public_key: String,
762 algorithm: u8,
763 events: Option<Events>,
764 links: Option<Vec<Link>>,
765}
766
767#[derive(Serialize, Deserialize, Debug)]
768#[serde(rename_all = "camelCase")]
769pub struct SecureDns {
770 zone_signed: Option<bool>,
771 delegation_signed: Option<bool>,
772 max_sig_life: Option<u32>,
773 ds_data: Option<Vec<DsData>>,
774 key_data: Option<Vec<KeyData>>,
775}
776
777#[derive(Serialize, Deserialize, Debug)]
779#[serde(rename_all = "camelCase")]
780pub struct FredKeyset {
781 pub links: Vec<Link>,
782 pub handle: String,
783 pub object_class_name: String,
784 #[serde(rename = "dns_keys")]
785 pub dns_keys: Vec<KeyData>,
786}
787
788#[derive(Serialize, Deserialize, Debug)]
790#[serde(rename_all = "camelCase")]
791pub struct FredNsset {
792 pub links: Vec<Link>,
793 pub handle: String,
794 pub object_class_name: String,
795 pub nameservers: Vec<Nameserver>,
796}
797
798#[derive(Serialize, Deserialize, Debug)]
800#[serde(rename_all = "camelCase")]
801pub struct Domain {
802 pub handle: Option<String>,
803 pub entities: Vec<Entity>,
804 pub links: Option<Vec<Link>>,
805 pub variants: Option<Vec<Variant>>,
806 pub nameservers: Option<Vec<Nameserver>>,
807 #[serde(rename = "secureDNS")]
808 pub secure_dns: Option<SecureDns>,
809 pub remarks: Option<NoticesOrRemarks>,
810 pub events: Events,
811 pub network: Option<IpNetwork>,
812 pub rdap_conformance: Option<Vec<String>>,
813 pub notices: Option<NoticesOrRemarks>,
814 pub port43: Option<String>,
815 pub status: Option<Vec<String>>,
816 pub lang: Option<String>,
817 pub object_class_name: String,
818 #[serde(rename = "fred_keyset")]
820 pub fred_keyset: Option<FredKeyset>,
821 #[serde(rename = "fred_nsset")]
822 pub fred_nsset: Option<FredNsset>,
823}
824
825#[derive(Serialize, Deserialize, Debug)]
827#[serde(rename_all = "camelCase")]
828pub struct Help {
829 rdap_conformance: Option<Vec<String>>,
830 notices: Option<NoticesOrRemarks>,
831}
832
833#[derive(Serialize, Deserialize, Debug)]
835#[serde(rename_all = "camelCase")]
836pub struct EntitySearchResults {
837 rdap_conformance: Option<Vec<String>>,
838 notices: Option<NoticesOrRemarks>,
839 #[serde(rename = "entitySearchResults")]
840 results: Vec<Entity>,
841}
842
843#[derive(Serialize, Deserialize, Debug)]
844#[serde(rename_all = "camelCase")]
845pub struct DomainSearchResults {
846 rdap_conformance: Option<Vec<String>>,
847 notices: Option<NoticesOrRemarks>,
848 #[serde(rename = "domainSearchResults")]
849 results: Vec<Entity>,
850}
851
852#[derive(Serialize, Deserialize, Debug)]
853#[serde(rename_all = "camelCase")]
854pub struct NameserverSearchResults {
855 rdap_conformance: Option<Vec<String>>,
856 notices: Option<NoticesOrRemarks>,
857 #[serde(rename = "nameserverSearchResults")]
858 results: Vec<Entity>,
859}
860
861#[derive(Serialize, Deserialize, Debug)]
862#[serde(rename_all = "camelCase")]
863pub struct ArinOriginas0OriginautnumsResults {
864 rdap_conformance: Option<Vec<String>>,
865 notices: Option<NoticesOrRemarks>,
866 #[serde(rename = "arin_originas0_networkSearchResults")]
867 results: Vec<IpNetwork>,
868}
869
870fn deserialize_error_code<'de, D>(deserializer: D) -> Result<u16, D::Error>
873where
874 D: Deserializer<'de>,
875{
876 struct ErrorCodeVisitor;
877
878 impl<'de> Visitor<'de> for ErrorCodeVisitor {
879 type Value = u16;
880
881 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
882 write!(formatter, "expecting an error code as string or number")
883 }
884
885 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
886 where
887 E: serde::de::Error,
888 {
889 u16::try_from(v).map_err(|_| {
890 serde::de::Error::invalid_value(Unexpected::Unsigned(v), &"an error code")
891 })
892 }
893
894 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
895 where
896 E: serde::de::Error,
897 {
898 u16::from_str(v)
899 .map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(v), &"an error code"))
900 }
901 }
902
903 deserializer.deserialize_any(ErrorCodeVisitor)
904}
905
906#[derive(Serialize, Deserialize, Debug)]
908#[serde(rename_all = "camelCase")]
909pub struct Error {
910 #[serde(deserialize_with = "deserialize_error_code")]
911 error_code: u16,
912 title: String,
913 description: Option<Vec<String>>,
914 rdap_conformance: Option<Vec<String>>,
915 notices: Option<NoticesOrRemarks>,
916 lang: Option<String>,
917}
918
919pub trait BootstrapService {
920 fn keys(&self) -> &Vec<String>;
921 fn servers(&self) -> &Vec<String>;
922}
923
924#[derive(Deserialize, Debug)]
925pub struct BootstrapServiceRfc7484(Vec<String>, Vec<String>);
926
927impl BootstrapService for BootstrapServiceRfc7484 {
928 fn keys(&self) -> &Vec<String> {
929 &self.0
930 }
931 fn servers(&self) -> &Vec<String> {
932 &self.1
933 }
934}
935
936#[derive(Deserialize, Debug)]
937pub struct BootstrapServiceRfc8521(Vec<String>, Vec<String>, Vec<String>);
938
939impl BootstrapService for BootstrapServiceRfc8521 {
940 fn keys(&self) -> &Vec<String> {
941 &self.1
942 }
943 fn servers(&self) -> &Vec<String> {
944 &self.2
945 }
946}
947
948#[derive(Deserialize, Debug)]
949pub struct Bootstrap<T> {
950 pub description: Option<String>,
951 pub publication: DateTime<FixedOffset>,
952 pub services: Vec<T>,
953 pub version: String,
954}
955
956pub type BootstrapRfc7484 = Bootstrap<BootstrapServiceRfc7484>;
958pub type BootstrapRfc8521 = Bootstrap<BootstrapServiceRfc8521>;
960
961#[cfg(test)]
962mod tests {
963 use super::*;
964 use serde::de::DeserializeOwned;
965 use std::fs::File;
966
967 #[test]
968 fn test_county_code() {
969 let country_code = CountryCode::from_str("CZ").unwrap();
970 assert_eq!(country_code.to_string(), "CZ");
971 assert_eq!(format!("{:?}", country_code), "CZ");
972 assert_eq!(country_code, CountryCode::from_str("cz").unwrap());
973
974 assert!(CountryCode::from_str("CZE").is_err());
975 assert!(CountryCode::from_str("C").is_err());
976 assert!(CountryCode::from_str("ČZ").is_err());
977 }
978
979 #[test]
980 fn test_country_code_serialize_deserialize() {
981 let item: CountryCode = serde_json::from_str(&"\"CZ\"").unwrap();
982 assert_eq!(item, CountryCode::from_str("CZ").unwrap());
983
984 let json = serde_json::to_string(&item).unwrap();
985 assert_eq!(json, "\"CZ\"");
986 }
987
988 #[test]
989 fn test_normalize_enum() {
990 let item: JCardItemDataType = serde_json::from_str(&"\"uri\"").unwrap();
991 assert_eq!(item, JCardItemDataType::Uri);
992
993 let item: JCardItemDataType = serde_json::from_str(&"\"URI\"").unwrap();
994 assert_eq!(item, JCardItemDataType::Uri);
995
996 let json = serde_json::to_string(&JCardItemDataType::Uri).unwrap();
997 assert_eq!(json, "\"uri\"");
998 }
999
1000 #[test]
1001 fn parse_vcard_multiple_values() {
1002 let json = r#"["vcard",[["version",{},"text","4.0"],["fn",{},"text",""],["adr",{"cc":"US","iso-3166-1-alpha-2":"US"},"text","","","","","Washington","",""],["org",{},"text","Amazon Registry Services, Inc."]]]"#;
1003 let jcard: JCard = serde_json::from_str(&json).unwrap();
1004 assert_eq!(jcard.typ(), JCardType::Vcard);
1005 assert_eq!(jcard.items().len(), 4);
1006
1007 assert_eq!(jcard.items_by_name("adr")[0].values.len(), 7);
1008 assert_eq!(
1009 jcard.items_by_name("org")[0].values[0],
1010 "Amazon Registry Services, Inc."
1011 );
1012
1013 let ser_json = serde_json::to_string(&jcard).unwrap();
1014 assert_eq!(json, ser_json);
1015 }
1016
1017 #[test]
1018 fn test_event_date_normal_format() {
1019 let json = r#"{"eventDate":"1990-12-31T23:59:59Z","eventAction":"last changed"}"#;
1020 let item: Event = serde_json::from_str(&json).unwrap();
1021 assert_eq!(item.event_date.to_rfc3339(), "1990-12-31T23:59:59+00:00");
1022 }
1023
1024 #[test]
1025 fn test_event_date_normal_format_with_timezone() {
1026 let json = r#"{"eventDate":"2011-07-05T12:48:24-04:00","eventAction":"last changed"}"#;
1027 let item: Event = serde_json::from_str(&json).unwrap();
1028 assert_eq!(item.event_date.to_rfc3339(), "2011-07-05T12:48:24-04:00");
1029 }
1030
1031 #[test]
1032 fn test_event_date_weird_format() {
1033 let json = r#"{"eventDate":"2019-09-20T11:45:06","eventAction":"last changed"}"#;
1034 let item: Event = serde_json::from_str(&json).unwrap();
1035 assert_eq!(item.event_date.to_rfc3339(), "2019-09-20T11:45:06+00:00");
1036 }
1037
1038 #[test]
1040 fn test_event_date_weird_format_vol2() {
1041 let json = r#"{"eventAction":"last changed","eventDate":"2016-04-13 08:18:43"}"#;
1042 let item: Event = serde_json::from_str(&json).unwrap();
1043 assert_eq!(item.event_date.to_rfc3339(), "2016-04-13T08:18:43+00:00");
1044 }
1045
1046 #[test]
1048 fn test_event_date_weird_format_vol3() {
1049 let json = r#"{"eventAction":"last changed","eventDate":"2015-08-25T00:00:00Z+0800"}"#;
1050 let item: Event = serde_json::from_str(&json).unwrap();
1051 assert_eq!(item.event_date.to_rfc3339(), "2015-08-25T00:00:00+08:00");
1052 }
1053
1054 #[test]
1055 fn test_notices_or_remarks() {
1056 let notices_or_remarks = NoticesOrRemarks(vec![NoticeOrRemark {
1057 title: Some("Title".into()),
1058 typ: None,
1059 description: Some(vec!["Ahoj".into()]),
1060 links: None,
1061 }]);
1062 assert_eq!(
1063 notices_or_remarks.description_by_title("title").unwrap()[0],
1064 "Ahoj"
1065 );
1066 assert!(notices_or_remarks.description_by_title("nothing").is_none());
1067 }
1068
1069 fn deserialize<T: DeserializeOwned>(path: &str) -> T {
1070 let file = File::open(format!("test_data/{}", path)).unwrap();
1071 let parsed: T = serde_json::from_reader(file).unwrap();
1072 parsed
1073 }
1074
1075 fn deserialize_and_serialize<T: DeserializeOwned + Serialize>(path: &str) -> T {
1076 let parsed = deserialize(path);
1077 serde_json::to_string(&parsed).unwrap();
1079 parsed
1080 }
1081
1082 #[test]
1083 fn test_parse_entity_15() {
1084 let parsed: Entity = deserialize_and_serialize("entity/entity_15.json");
1085 assert_eq!("XXXX", parsed.handle.as_ref().unwrap());
1086 assert_eq!(1, parsed.as_event_actor.as_ref().unwrap().0.len());
1087 }
1088
1089 #[test]
1090 fn test_parse_entity_17() {
1091 let parsed: Entity = deserialize_and_serialize("entity/entity_17.json");
1092 assert_eq!("XXXX", parsed.handle.as_ref().unwrap());
1093 }
1094
1095 #[test]
1096 fn test_parse_entity_fred() {
1097 let parsed: Entity = deserialize_and_serialize("entity/entity_fred.json");
1098 assert_eq!("CZ-NIC", parsed.handle.as_ref().unwrap());
1099 }
1100
1101 #[test]
1102 fn test_parse_entity_ripe() {
1103 let parsed: Entity = deserialize_and_serialize("entity/entity_ripe.json");
1104 assert_eq!("ORG-RIEN1-RIPE", parsed.handle.as_ref().unwrap());
1105 }
1106
1107 #[test]
1108 fn test_parse_nameserver_18() {
1109 let parsed: Nameserver = deserialize_and_serialize("nameserver/nameserver_18.json");
1110 assert_eq!("XXXX", parsed.handle.unwrap());
1111 }
1112
1113 #[test]
1114 fn test_parse_nameserver_19() {
1115 let parsed: Nameserver = deserialize_and_serialize("nameserver/nameserver_19.json");
1116 assert_eq!("ns1.example.com", parsed.ldh_name);
1117 }
1118
1119 #[test]
1120 fn test_parse_nameserver_20() {
1121 let parsed: Nameserver = deserialize_and_serialize("nameserver/nameserver_20.json");
1122 assert_eq!("ns1.example.com", parsed.ldh_name);
1123 }
1124
1125 #[test]
1126 fn test_parse_nameserver_fred() {
1127 let parsed: Nameserver = deserialize_and_serialize("nameserver/nameserver_fred.json");
1128 assert_eq!("a.ns.nic.cz", parsed.ldh_name);
1129 }
1130
1131 #[test]
1132 fn test_parse_domain_23() {
1133 let parsed: Domain = deserialize_and_serialize("domain/domain_23.json");
1134 assert_eq!("XXXX", parsed.handle.unwrap());
1135 }
1136
1137 #[test]
1138 fn test_parse_domain_24() {
1139 let parsed: Domain = deserialize_and_serialize("domain/domain_24.json");
1140 assert_eq!("XXXX", parsed.handle.unwrap());
1141 }
1142
1143 #[test]
1144 fn test_parse_domain_fred() {
1145 let parsed: Domain = deserialize_and_serialize("domain/domain_fred.json");
1146 assert_eq!("nic.cz", parsed.handle.unwrap());
1147 }
1148
1149 #[test]
1150 fn test_parse_domain_ripe_reverse() {
1151 let parsed: Domain = deserialize_and_serialize("domain/domain_ripe_reverse.json");
1152 assert_eq!("6.0.193.in-addr.arpa", parsed.handle.unwrap());
1153 }
1154
1155 #[test]
1156 fn test_parse_ip_network_26() {
1157 let parsed: IpNetwork = deserialize_and_serialize("ip_network/ip_network_26.json");
1158 assert_eq!("XXXX-RIR", parsed.handle);
1159 }
1160
1161 #[test]
1162 fn test_parse_ip_network_apnic_1_1_1_1() {
1163 let parsed: IpNetwork =
1164 deserialize_and_serialize("ip_network/ip_network_apnic_1_1_1_1.json");
1165 assert_eq!("1.1.1.0 - 1.1.1.255", parsed.handle);
1166 }
1167
1168 #[test]
1169 fn test_parse_ip_network_arin_3_3_3_3() {
1170 let parsed: IpNetwork =
1171 deserialize_and_serialize("ip_network/ip_network_arin_3_3_3_3.json");
1172 assert_eq!("NET-3-0-0-0-1", parsed.handle);
1173 }
1174
1175 #[test]
1176 fn test_parse_ip_network_ripe_193_0_0_0() {
1177 let parsed: IpNetwork =
1178 deserialize_and_serialize("ip_network/ip_network_ripe_193_0_0_0.json");
1179 assert_eq!("193.0.0.0 - 193.0.7.255", parsed.handle);
1180 }
1181
1182 #[test]
1183 fn test_parse_ip_network_afrinic() {
1184 let parsed: IpNetwork = deserialize_and_serialize("ip_network/ip_network_afrinic.json");
1185 assert_eq!("41.0.0.0 - 41.0.255.255", parsed.handle);
1186 }
1187
1188 #[test]
1189 fn test_parse_ip_network_br() {
1190 let parsed: IpNetwork = deserialize_and_serialize("ip_network/ip_network_br.json");
1191 assert_eq!("177.0.0.0/14", parsed.handle);
1192 }
1193
1194 #[test]
1195 fn test_parse_ip_network_lacnic() {
1196 let parsed: IpNetwork = deserialize_and_serialize("ip_network/ip_network_lacnic.json");
1197 assert_eq!("179.0.0.0/23", parsed.handle);
1198 }
1199
1200 #[test]
1201 fn test_parse_autnum_27() {
1202 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_27.json");
1203 assert_eq!("XXXX-RIR", parsed.handle);
1204 }
1205
1206 #[test]
1207 fn test_parse_autnum_ripe_as1234() {
1208 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_ripe_as1234.json");
1209 assert_eq!("AS1234", parsed.handle);
1210 }
1211
1212 #[test]
1213 fn test_parse_autnum_arin_as256() {
1214 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_arin_as256.json");
1215 assert_eq!("AS256", parsed.handle);
1216 }
1217
1218 #[test]
1219 fn test_parse_autnum_afrinic_as36864() {
1220 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_afrinic_as36864.json");
1221 assert_eq!("AS36864", parsed.handle);
1222 }
1223
1224 #[test]
1225 fn test_parse_autnum_apnic_as4608() {
1226 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_apnic_as4608.json");
1227 assert_eq!("AS4608", parsed.handle);
1228 }
1229
1230 #[test]
1231 fn test_parse_autnum_lacnic_as27648() {
1232 let parsed: AutNum = deserialize_and_serialize("autnum/autnum_lacnic_as27648.json");
1233 assert_eq!("27648", parsed.handle);
1234 }
1235
1236 #[test]
1237 fn test_parse_arin_originas0_network_search_results() {
1238 let parsed: ArinOriginas0OriginautnumsResults =
1239 deserialize_and_serialize("arin_originas0_networkSearchResults.json");
1240 assert!(parsed.results.len() > 0);
1241 }
1242
1243 #[test]
1244 fn test_parse_error_28() {
1245 let parsed: Error = deserialize_and_serialize("error/error_28.json");
1246 assert_eq!(418, parsed.error_code);
1247 }
1248
1249 #[test]
1250 fn test_parse_error_29() {
1251 let parsed: Error = deserialize_and_serialize("error/error_29.json");
1252 assert_eq!(418, parsed.error_code);
1253 }
1254
1255 #[test]
1256 fn test_parse_error_apnic_400() {
1257 let parsed: Error = deserialize_and_serialize("error/error_apnic_400.json");
1258 assert_eq!(400, parsed.error_code);
1259 }
1260
1261 #[test]
1262 fn test_parse_error_ripe_404() {
1263 let parsed: Error = deserialize_and_serialize("error/error_ripe_404.json");
1264 assert_eq!(404, parsed.error_code);
1265 }
1266
1267 #[test]
1268 fn test_parse_bootstrap_asn() {
1269 let parsed: BootstrapRfc7484 = deserialize("bootstrap/asn.json");
1270 assert!(parsed.services.len() > 0);
1271 }
1272
1273 #[test]
1274 fn test_parse_bootstrap_dns() {
1275 let parsed: BootstrapRfc7484 = deserialize("bootstrap/dns.json");
1276 assert!(parsed.services.len() > 0);
1277 }
1278
1279 #[test]
1280 fn test_parse_bootstrap_ipv4() {
1281 let parsed: BootstrapRfc7484 = deserialize("bootstrap/ipv4.json");
1282 assert!(parsed.services.len() > 0);
1283 }
1284
1285 #[test]
1286 fn test_parse_bootstrap_ipv6() {
1287 let parsed: BootstrapRfc7484 = deserialize("bootstrap/ipv6.json");
1288 assert!(parsed.services.len() > 0);
1289 }
1290
1291 #[test]
1292 fn test_parse_bootstrap_object_tags() {
1293 let parsed: BootstrapRfc8521 = deserialize("bootstrap/object-tags.json");
1294 assert!(parsed.services.len() > 0);
1295 }
1296}