diff --git a/Makefile b/Makefile index 551bb55..cb16a57 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ coverage-check: coverage-setup @COVERAGE=$$(grep "TOTAL" coverage_summary.txt | grep -oE '[0-9]+\.[0-9]+%' | tail -1 | sed 's/%//'); \ THRESHOLD=90.0; \ if [ -z "$$COVERAGE" ]; then \ - echo "โŒ Could not extract total coverage percentage"; \ + echo "ERROR: Could not extract total coverage percentage"; \ cat coverage_summary.txt; \ rm -f coverage_summary.txt; \ exit 1; \ @@ -122,11 +122,11 @@ coverage-check: coverage-setup echo "Current coverage: $${COVERAGE}%"; \ echo "Minimum threshold: $${THRESHOLD}%"; \ if [ $$(echo "$${COVERAGE} < $${THRESHOLD}" | bc -l) -eq 1 ]; then \ - echo "โŒ Coverage $${COVERAGE}% is below threshold $${THRESHOLD}%"; \ + echo "FAIL: Coverage $${COVERAGE}% is below threshold $${THRESHOLD}%"; \ rm -f coverage_summary.txt; \ exit 1; \ else \ - echo "โœ… Coverage $${COVERAGE}% meets threshold $${THRESHOLD}%"; \ + echo "PASS: Coverage $${COVERAGE}% meets threshold $${THRESHOLD}%"; \ rm -f coverage_summary.txt; \ fi @@ -145,60 +145,60 @@ docs: # Developer setup - install Rust and set up development environment developer: - @echo "๐Ÿš€ Setting up development environment..." + @echo "Setting up development environment..." @if command -v rustc > /dev/null 2>&1; then \ - echo "โœ… Rust is already installed (version: $$(rustc --version))"; \ + echo "Rust is already installed (version: $$(rustc --version))"; \ else \ - echo "๐Ÿ“ฆ Installing Rust via rustup (automated)..."; \ + echo "Installing Rust via rustup (automated)..."; \ if [ -f scripts/rustup-init.sh ]; then \ chmod +x scripts/rustup-init.sh; \ ./scripts/rustup-init.sh -y --default-toolchain stable; \ - echo "๐Ÿ”„ Rust installed! Sourcing environment..."; \ + echo "Rust installed! Sourcing environment..."; \ . "$$HOME/.cargo/env" 2>/dev/null || true; \ else \ - echo "โŒ scripts/rustup-init.sh not found in project root."; \ - echo " Please download it from: https://sh.rustup.rs/"; \ + echo "ERROR: scripts/rustup-init.sh not found in project root."; \ + echo " Please download it from: https://sh.rustup.rs/"; \ exit 1; \ fi; \ fi - @echo "๐Ÿ”ง Setting up development tools..." + @echo "Setting up development tools..." @if command -v rustc > /dev/null 2>&1; then \ - echo "๐Ÿ“‹ Rust version: $$(rustc --version)"; \ - echo "๐Ÿ“‹ Cargo version: $$(cargo --version)"; \ - echo "๐Ÿงช Installing development tools..."; \ + echo "Rust version: $$(rustc --version)"; \ + echo "Cargo version: $$(cargo --version)"; \ + echo "Installing development tools..."; \ $(MAKE) coverage-setup; \ - cargo install cargo-audit --quiet || echo "โš ๏ธ cargo-audit installation failed or already installed"; \ - echo "๐Ÿ”ง Installing script dependencies..."; \ + cargo install cargo-audit --quiet || echo "WARNING: cargo-audit installation failed or already installed"; \ + echo "Installing script dependencies..."; \ if ! command -v jq > /dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Installing jq..."; \ + echo "Installing jq..."; \ if command -v brew > /dev/null 2>&1; then \ brew install jq; \ else \ - echo "โš ๏ธ Please install jq manually: https://stedolan.github.io/jq/download/"; \ + echo "WARNING: Please install jq manually: https://stedolan.github.io/jq/download/"; \ fi; \ else \ - echo "โœ… jq is already installed"; \ + echo "jq is already installed"; \ fi; \ if ! command -v curl > /dev/null 2>&1; then \ - echo "๐Ÿ“ฆ Installing curl..."; \ + echo "Installing curl..."; \ if command -v brew > /dev/null 2>&1; then \ brew install curl; \ else \ - echo "โš ๏ธ Please install curl manually"; \ + echo "WARNING: Please install curl manually"; \ fi; \ else \ - echo "โœ… curl is already installed"; \ + echo "curl is already installed"; \ fi; \ - echo "๐Ÿ—๏ธ Running initial build and test..."; \ + echo "Running initial build and test..."; \ $(MAKE) check; \ $(MAKE) test; \ echo ""; \ - echo "โœ… Development environment setup complete!"; \ + echo "Development environment setup complete!"; \ else \ - echo "โš ๏ธ Rust installation completed but not available in current shell."; \ - echo "๐Ÿ”„ Please restart your shell or run:"; \ - echo " source $$HOME/.cargo/env"; \ - echo " make developer"; \ + echo "WARNING: Rust installation completed but not available in current shell."; \ + echo "Please restart your shell or run:"; \ + echo " source $$HOME/.cargo/env"; \ + echo " make developer"; \ fi $(MAKE) help diff --git a/keetanetwork-asn1/asn1/iso20022.asn b/keetanetwork-asn1/asn1/iso20022.asn index ccd1eed..fe5f432 100644 --- a/keetanetwork-asn1/asn1/iso20022.asn +++ b/keetanetwork-asn1/asn1/iso20022.asn @@ -11,6 +11,9 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN Department ::= UTF8String --1.3.6.1.4.1.62675.1.2.9 EmailAddressPurpose ::= UTF8String --1.3.6.1.4.1.62675.1.3.0 FullName ::= UTF8String --1.3.6.1.4.1.62675.1.0 + FirstName ::= UTF8String --1.3.6.1.4.1.62675.1.0.1 + LastName ::= UTF8String --1.3.6.1.4.1.62675.1.0.2 + MiddleName ::= UTF8String --1.3.6.1.4.1.62675.1.0.3 BirthDate ::= GeneralizedTime --1.3.6.1.4.1.62675.1.1 EmailAddress ::= UTF8String --1.3.6.1.4.1.62675.1.3 PhoneNumber ::= UTF8String --1.3.6.1.4.1.62675.1.4 @@ -18,6 +21,7 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN JobResponsibility ::= UTF8String --1.3.6.1.4.1.62675.1.6.1 Id ::= UTF8String --1.3.6.1.4.1.62675.1.7 Issuer ::= UTF8String --1.3.6.1.4.1.62675.1.7.1 + Nationality ::= UTF8String --1.3.6.1.4.1.62675.1.10 AddressType ::= CHOICE { -- 1.3.6.1.4.1.62675.1.2.10 code [0] EXPLICIT UTF8String, @@ -31,7 +35,23 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN PersonIdentificationSchemeNameChoice ::= CHOICE { -- 1.3.6.1.4.1.62675.1.8.1.1 code [0] EXPLICIT UTF8String, - proprietary [1] EXPLICIT UTF8String + proprietary [1] EXPLICIT PersonIdentificationSchemeNameProprietary + } + + DigestInfo ::= SEQUENCE { + digestAlgorithm [0] EXPLICIT OBJECT IDENTIFIER, + digest [1] EXPLICIT OCTET STRING + } + + ExternalReference ::= SEQUENCE { + url [0] EXPLICIT UTF8String, + contentType [1] EXPLICIT UTF8String + } + + Reference ::= SEQUENCE { + external [0] EXPLICIT ExternalReference, + digest [1] EXPLICIT DigestInfo, + encryptionAlgorithm [2] EXPLICIT OBJECT IDENTIFIER } Address ::= SEQUENCE { --1.3.6.1.4.1.62675.1.2 @@ -54,6 +74,11 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN provinceOfBirth [3] EXPLICIT CountrySubDivision OPTIONAL } + EntityType ::= SEQUENCE { --1.3.6.1.4.1.62675.1.8 + organization [0] EXPLICIT SEQUENCE OF GenericOrganizationIdentification OPTIONAL, + person [1] EXPLICIT SEQUENCE OF GenericPersonIdentification OPTIONAL + } + ContactDetails ::= SEQUENCE { --1.3.6.1.4.1.62675.1.9 department [0] EXPLICIT Department OPTIONAL, emailAddress [1] EXPLICIT EmailAddress OPTIONAL, @@ -69,6 +94,30 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN preferredMethod [11] EXPLICIT PreferredContactMethodCode OPTIONAL } + Document ::= SEQUENCE { --1.3.6.1.4.1.62675.1.11 + documentNumber [0] EXPLICIT UTF8String, + front [1] EXPLICIT Reference OPTIONAL, + back [2] EXPLICIT Reference OPTIONAL, + selfie [3] EXPLICIT Reference OPTIONAL, + fullName [4] EXPLICIT UTF8String OPTIONAL, + firstName [5] EXPLICIT UTF8String OPTIONAL, + lastName [6] EXPLICIT UTF8String OPTIONAL, + dob [7] EXPLICIT GeneralizedTime OPTIONAL, + gender [8] EXPLICIT UTF8String OPTIONAL, + address [9] EXPLICIT Address OPTIONAL, + expiresAt [10] EXPLICIT GeneralizedTime OPTIONAL, + issuedAt [11] EXPLICIT GeneralizedTime OPTIONAL, + issuingState [12] EXPLICIT UTF8String OPTIONAL, + issuingCountry [13] EXPLICIT UTF8String OPTIONAL, + refNumber [14] EXPLICIT UTF8String OPTIONAL, + nationality [15] EXPLICIT UTF8String OPTIONAL, + curp [16] EXPLICIT UTF8String OPTIONAL, + claveDeElector [17] EXPLICIT UTF8String OPTIONAL, + classifiedDocumentType [18] EXPLICIT UTF8String OPTIONAL, + curpValidationResponse [19] EXPLICIT UTF8String OPTIONAL, + sambaActivityHistoryResponse [20] EXPLICIT UTF8String OPTIONAL + } + OrganizationIdentification ::= SEQUENCE { --1.3.6.1.4.1.62675.1.8.0 bic [0] EXPLICIT UTF8String OPTIONAL, lei [1] EXPLICIT UTF8String OPTIONAL, @@ -97,15 +146,14 @@ Iso20022 DEFINITIONS AUTOMATIC TAGS ::= BEGIN id [1] EXPLICIT Id OPTIONAL } - EntityType ::= CHOICE { --1.3.6.1.4.1.62675.1.8 - organization [0] EXPLICIT OrganizationIdentification, - person [1] EXPLICIT PersonIdentification - } - NamePrefixCode ::= ENUMERATED { --1.3.6.1.4.1.62675.1.0.0 DOCT, MIST, MISS, MIKS, MME } + PersonIdentificationSchemeNameProprietary ::= ENUMERATED { --1.3.6.1.4.1.62675.1.8.1.1.0 + DRLC, CPPT, ARNU, SSN, TXID, VISA, WPPT + } + PreferredContactMethodCode ::= ENUMERATED { --1.3.6.1.4.1.62675.1.9.0 LETT, MAIL, PHON, FAXX, CELL } diff --git a/keetanetwork-asn1/build.rs b/keetanetwork-asn1/build.rs index 558d2c0..ae7e30f 100644 --- a/keetanetwork-asn1/build.rs +++ b/keetanetwork-asn1/build.rs @@ -82,6 +82,7 @@ fn generate_schema() { schema_content.push('\n'); generate_choice_types(&oids, &mut schema_content); + generate_extension_types(&oids, &mut schema_content); generate_sensitive_sequence_types(&oids, &mut schema_content); generate_iso20022_sequence_types(&oids, &mut schema_content); generate_sensitive_choice_types(&oids, &mut schema_content); @@ -194,6 +195,50 @@ fn generate_iso20022_sequence_types(oids: &Value, schema_content: &mut String) { } } +fn generate_extension_types(oids: &Value, schema_content: &mut String) { + let Some(extensions) = oids["extensions"].as_object() else { + return; + }; + + // Collect extension type names for dependency resolution + let extension_type_names: std::collections::HashSet<_> = extensions + .iter() + .filter(|(_, info)| info["fields"].is_object()) + .map(|(name, _)| name.as_str()) + .collect(); + + // Filter extensions that have fields (actual type definitions) + let mut extension_types: Vec<_> = extensions + .iter() + .filter(|(_, info)| info["fields"].is_object()) + .collect(); + + // Sort by dependency depth: types with fewer extension dependencies come first + extension_types.sort_by_key(|(_, info)| { + info["fields"] + .as_object() + .map(|fields| { + fields + .values() + .filter(|field_info| { + field_info["type"] + .as_str() + .is_some_and(|t| extension_type_names.contains(t)) + }) + .count() + }) + .unwrap_or(0) + }); + + for (name, info) in extension_types { + if let Some(fields) = info["fields"].as_object() { + schema_content.push_str(&format!(" {name} ::= SEQUENCE {{\n")); + generate_sequence_fields_with_context_tags(schema_content, fields, info.get("field_order")); + close_asn1_structure(schema_content); + } + } +} + fn generate_sensitive_choice_types(oids: &Value, schema_content: &mut String) { if let Some(sensitive_attrs) = oids["sensitive_attributes"].as_object() { let mut choice_attrs: Vec<_> = sensitive_attrs @@ -570,54 +615,77 @@ fn generate_from_impl_for_type(generated_code: &mut String, wrapper_types: &[Str } } +/// Helper to get ordered field names from field_order or fallback to keys +fn get_ordered_field_names(fields: &serde_json::Map, field_order_value: Option<&Value>) -> Vec { + if let Some(order_array) = field_order_value.and_then(|v| v.as_array()) { + order_array + .iter() + .filter_map(|v| v.as_str()) + .map(|s| s.to_string()) + .collect() + } else { + fields.keys().cloned().collect() + } +} + +/// Types that typically implement Default in rasn +const DEFAULT_TYPES: [&str; 9] = + ["String", "UTF8String", "Utf8String", "Vec", "SequenceOf", "BooleanType", "Integer", "BitString", "OctetString"]; + +/// Collect all enumerated type names from oids.json +fn collect_enumerated_types(oids: &Value) -> std::collections::HashSet { + let mut enum_types = std::collections::HashSet::new(); + if let Some(enumerations) = oids["iso20022_types"]["enumerations"].as_object() { + enum_types.extend(enumerations.keys().cloned()); + } + + enum_types +} + +/// Generate field defaults for a SEQUENCE type, returns None if type cannot implement Default +fn generate_field_defaults( + fields: &serde_json::Map, + field_order_value: Option<&Value>, + enum_types: &std::collections::HashSet, +) -> Option> { + let field_order = get_ordered_field_names(fields, field_order_value); + let mut field_defaults = Vec::new(); + for field_name in field_order { + let Some(field_info) = fields.get(&field_name) else { + continue; + }; + + let is_optional = field_info["optional"].as_bool().unwrap_or(false); + let field_type = field_info["type"].as_str().unwrap_or(""); + if is_optional { + field_defaults.push("None".to_string()); + } else { + // Check if the required field type implements Default + let is_default_primitive = DEFAULT_TYPES.iter().any(|&t| field_type.contains(t)); + let is_enum_type = enum_types.contains(field_type); + if is_default_primitive || is_enum_type { + field_defaults.push("Default::default()".to_string()); + } else { + return None; + } + } + } + + Some(field_defaults) +} + fn generate_default_impl(oids: &Value, generated_code: &mut String) { generated_code.push_str("// Default implementations for types with default fields\n\n"); - // Types that typically implement Default in rasn - let default_types = [ - "String", - "UTF8String", - "Utf8String", - "Vec", - "SequenceOf", - "BooleanType", - "Integer", - "BitString", - "OctetString", - ]; - - // Check sensitive_attributes for SEQUENCE types + let enum_types = collect_enumerated_types(oids); if let Some(sensitive_attrs) = oids["sensitive_attributes"].as_object() { for (name, attr_info) in sensitive_attrs { if attr_info["type"] == "SEQUENCE" { if let Some(fields) = attr_info["fields"].as_object() { let token = attr_info["token"].as_str().unwrap_or(name); - - // Check if we can generate Default for this type - let mut can_default = true; - let mut field_defaults = Vec::new(); - - for (_field_name, field_info) in fields { - let is_optional = field_info["optional"].as_bool().unwrap_or(false); - let field_type = field_info["type"].as_str().unwrap_or(""); - - if is_optional { - field_defaults.push("None".to_string()); - } else { - // Check if the required field type implements Default - if default_types.iter().any(|&t| field_type.contains(t)) - || field_type == "NamePrefixCode" - || field_type == "PreferredContactMethodCode" - { - field_defaults.push("Default::default()".to_string()); - } else { - can_default = false; - break; - } - } - } - - if can_default { + if let Some(field_defaults) = + generate_field_defaults(fields, attr_info.get("field_order"), &enum_types) + { generated_code.push_str(&format!( r#"impl Default for {token} {{ fn default() -> Self {{ @@ -638,30 +706,8 @@ fn generate_default_impl(oids: &Value, generated_code: &mut String) { if let Some(iso_types) = oids["iso20022_types"]["sequences"].as_object() { for (name, type_info) in iso_types { if let Some(fields) = type_info["fields"].as_object() { - let mut can_default = true; - let mut field_defaults = Vec::new(); - - for (_field_name, field_info) in fields { - let is_optional = field_info["optional"].as_bool().unwrap_or(false); - let field_type = field_info["type"].as_str().unwrap_or(""); - - if is_optional { - field_defaults.push("None".to_string()); - } else { - // Check if the required field type implements Default - if default_types.iter().any(|&t| field_type.contains(t)) - || field_type == "NamePrefixCode" - || field_type == "PreferredContactMethodCode" - { - field_defaults.push("Default::default()".to_string()); - } else { - can_default = false; - break; - } - } - } - - if can_default { + if let Some(field_defaults) = generate_field_defaults(fields, type_info.get("field_order"), &enum_types) + { generated_code.push_str(&format!( r#"impl Default for {name} {{ fn default() -> Self {{ @@ -786,6 +832,14 @@ use crate::generated::iso20022::*; ensure_single_newline_ending(&mut generated_code); fs::write(&dest_path, generated_code).unwrap_or_else(|_| panic!("Failed to write {filename}")); + // Format the generated file + if let Err(e) = std::process::Command::new("rustfmt") + .arg(&dest_path) + .status() + { + eprintln!("Warning: rustfmt failed: {}", e); + } + // Update generated.rs to include this module update_generated_rs_with_from_imp(filename); } diff --git a/keetanetwork-asn1/oids.json b/keetanetwork-asn1/oids.json index 0417ede..3b0205c 100644 --- a/keetanetwork-asn1/oids.json +++ b/keetanetwork-asn1/oids.json @@ -20,6 +20,27 @@ "description": "Person's full name", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.0" }, + "firstName": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 0, 1 ], + "token": "FirstName", + "type": "UTF8String", + "description": "Person's first name", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.0.1" + }, + "lastName": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 0, 2 ], + "token": "LastName", + "type": "UTF8String", + "description": "Person's last name", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.0.2" + }, + "middleName": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 0, 3 ], + "token": "MiddleName", + "type": "UTF8String", + "description": "Person's middle name", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.0.3" + }, "dateOfBirth": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 1 ], "token": "BirthDate", @@ -34,16 +55,46 @@ "description": "Physical address", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.2", "fields": { - "addressType": { "type": "AddressType", "optional": true }, - "department": { "type": "Department", "optional": true }, - "subDepartment": { "type": "SubDepartment", "optional": true }, - "streetName": { "type": "StreetName", "optional": true }, - "buildingNumber": { "type": "BuildingNumber", "optional": true }, - "postalCode": { "type": "PostalCode", "optional": true }, - "townName": { "type": "TownName", "optional": true }, - "countrySubDivision": { "type": "CountrySubDivision", "optional": true }, - "country": { "type": "Country", "optional": true }, - "addressLines": { "type": "AddressLines", "optional": true } + "addressType": { + "type": "AddressType", + "optional": true + }, + "department": { + "type": "Department", + "optional": true + }, + "subDepartment": { + "type": "SubDepartment", + "optional": true + }, + "streetName": { + "type": "StreetName", + "optional": true + }, + "buildingNumber": { + "type": "BuildingNumber", + "optional": true + }, + "postalCode": { + "type": "PostalCode", + "optional": true + }, + "townName": { + "type": "TownName", + "optional": true + }, + "countrySubDivision": { + "type": "CountrySubDivision", + "optional": true + }, + "country": { + "type": "Country", + "optional": true + }, + "addressLines": { + "type": "AddressLines", + "optional": true + } }, "field_order": [ "addressLines", @@ -79,10 +130,22 @@ "description": "Date and place of birth information", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.5", "fields": { - "birthDate": { "type": "BirthDate", "optional": false }, - "provinceOfBirth": { "type": "CountrySubDivision", "optional": true }, - "cityOfBirth": { "type": "TownName", "optional": false }, - "countryOfBirth": { "type": "Country", "optional": false } + "birthDate": { + "type": "BirthDate", + "optional": false + }, + "provinceOfBirth": { + "type": "CountrySubDivision", + "optional": true + }, + "cityOfBirth": { + "type": "TownName", + "optional": false + }, + "countryOfBirth": { + "type": "Country", + "optional": false + } }, "field_order": [ "birthDate", @@ -122,13 +185,23 @@ "entityType": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 8 ], "token": "EntityType", - "type": "CHOICE", + "type": "SEQUENCE", "description": "Entity type (organization or person)", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.8", - "choices": { - "organization": { "type": "OrganizationIdentification" }, - "person": { "type": "PersonIdentification" } - } + "fields": { + "organization": { + "type": "SEQUENCE OF GenericOrganizationIdentification", + "optional": true + }, + "person": { + "type": "SEQUENCE OF GenericPersonIdentification", + "optional": true + } + }, + "field_order": [ + "organization", + "person" + ] }, "contactDetails": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 9 ], @@ -137,18 +210,54 @@ "description": "Contact details", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.9", "fields": { - "namePrefix": { "type": "NamePrefixCode", "optional": true }, - "fullName": { "type": "FullName", "optional": true }, - "phoneNumber": { "type": "PhoneNumber", "optional": true }, - "mobileNumber": { "type": "PhoneNumber", "optional": true }, - "faxNumber": { "type": "PhoneNumber", "optional": true }, - "emailAddress": { "type": "EmailAddress", "optional": true }, - "emailPurpose": { "type": "EmailAddressPurpose", "optional": true }, - "jobTitle": { "type": "JobTitle", "optional": true }, - "jobResponsibility": { "type": "JobResponsibility", "optional": true }, - "department": { "type": "Department", "optional": true }, - "other": { "type": "SEQUENCE OF OtherContact", "optional": true }, - "preferredMethod": { "type": "PreferredContactMethodCode", "optional": true } + "namePrefix": { + "type": "NamePrefixCode", + "optional": true + }, + "fullName": { + "type": "FullName", + "optional": true + }, + "phoneNumber": { + "type": "PhoneNumber", + "optional": true + }, + "mobileNumber": { + "type": "PhoneNumber", + "optional": true + }, + "faxNumber": { + "type": "PhoneNumber", + "optional": true + }, + "emailAddress": { + "type": "EmailAddress", + "optional": true + }, + "emailPurpose": { + "type": "EmailAddressPurpose", + "optional": true + }, + "jobTitle": { + "type": "JobTitle", + "optional": true + }, + "jobResponsibility": { + "type": "JobResponsibility", + "optional": true + }, + "department": { + "type": "Department", + "optional": true + }, + "other": { + "type": "SEQUENCE OF OtherContact", + "optional": true + }, + "preferredMethod": { + "type": "PreferredContactMethodCode", + "optional": true + } }, "field_order": [ "department", @@ -164,6 +273,178 @@ "phoneNumber", "preferredMethod" ] + }, + "nationality": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 10 ], + "token": "Nationality", + "type": "UTF8String", + "description": "Nationality", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.10" + }, + "document": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11 ], + "type": "SEQUENCE", + "token": "Document", + "description": "Generic document structure with metadata", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11", + "fields": { + "documentNumber": { + "type": "UTF8String", + "optional": false + }, + "front": { + "type": "Reference", + "optional": true + }, + "back": { + "type": "Reference", + "optional": true + }, + "selfie": { + "type": "Reference", + "optional": true + }, + "fullName": { + "type": "UTF8String", + "optional": true + }, + "firstName": { + "type": "UTF8String", + "optional": true + }, + "lastName": { + "type": "UTF8String", + "optional": true + }, + "dob": { + "type": "GeneralizedTime", + "optional": true + }, + "gender": { + "type": "UTF8String", + "optional": true + }, + "address": { + "type": "Address", + "optional": true + }, + "expiresAt": { + "type": "GeneralizedTime", + "optional": true + }, + "issuedAt": { + "type": "GeneralizedTime", + "optional": true + }, + "issuingState": { + "type": "UTF8String", + "optional": true + }, + "issuingCountry": { + "type": "UTF8String", + "optional": true + }, + "refNumber": { + "type": "UTF8String", + "optional": true + }, + "nationality": { + "type": "UTF8String", + "optional": true + }, + "curp": { + "type": "UTF8String", + "optional": true + }, + "claveDeElector": { + "type": "UTF8String", + "optional": true + }, + "classifiedDocumentType": { + "type": "UTF8String", + "optional": true + }, + "curpValidationResponse": { + "type": "UTF8String", + "optional": true + }, + "sambaActivityHistoryResponse": { + "type": "UTF8String", + "optional": true + } + }, + "field_order": [ + "documentNumber", + "front", + "back", + "selfie", + "fullName", + "firstName", + "lastName", + "dob", + "gender", + "address", + "expiresAt", + "issuedAt", + "issuingState", + "issuingCountry", + "refNumber", + "nationality", + "curp", + "claveDeElector", + "classifiedDocumentType", + "curpValidationResponse", + "sambaActivityHistoryResponse" + ] + }, + "documentDriversLicense": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 0 ], + "token": "DocumentDriversLicense", + "type": "Document", + "description": "Driver's license document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.0" + }, + "documentIdCard": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 1 ], + "token": "DocumentIdCard", + "type": "Document", + "description": "ID card document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.1" + }, + "documentPassport": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 2 ], + "token": "DocumentPassport", + "type": "Document", + "description": "Passport document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.2" + }, + "documentPassportCard": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 3 ], + "token": "DocumentPassportCard", + "type": "Document", + "description": "Passport card document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.3" + }, + "documentPermit": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 4 ], + "token": "DocumentPermit", + "type": "Document", + "description": "Permit document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.4" + }, + "documentVisa": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 5 ], + "token": "DocumentVisa", + "type": "Document", + "description": "Visa document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.5" + }, + "documentResidenceDocument": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 11, 6 ], + "token": "DocumentResidenceDocument", + "type": "Document", + "description": "Residence document", + "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.1.11.6" } }, "iso20022_types": { @@ -225,8 +506,12 @@ "type": "CHOICE", "description": "Address type classification", "choices": { - "code": { "type": "UTF8String" }, - "proprietary": { "type": "UTF8String" } + "code": { + "type": "UTF8String" + }, + "proprietary": { + "type": "UTF8String" + } } }, "OrganizationIdentificationSchemeNameChoice": { @@ -234,8 +519,12 @@ "type": "CHOICE", "description": "Organization identification scheme name", "choices": { - "code": { "type": "UTF8String" }, - "proprietary": { "type": "UTF8String" } + "code": { + "type": "UTF8String" + }, + "proprietary": { + "type": "UTF8String" + } } }, "PersonIdentificationSchemeNameChoice": { @@ -243,8 +532,12 @@ "type": "CHOICE", "description": "Person identification scheme name", "choices": { - "code": { "type": "UTF8String" }, - "proprietary": { "type": "UTF8String" } + "code": { + "type": "UTF8String" + }, + "proprietary": { + "type": "PersonIdentificationSchemeNameProprietary" + } } } }, @@ -253,13 +546,39 @@ "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 0, 0 ], "type": "ENUMERATED", "description": "Name prefix code", - "values": [ "DOCT", "MIST", "MISS", "MIKS", "MME" ] + "values": [ + "DOCT", + "MIST", + "MISS", + "MIKS", + "MME" + ] }, "PreferredContactMethodCode": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 9, 0 ], "type": "ENUMERATED", "description": "Preferred contact method", - "values": [ "LETT", "MAIL", "PHON", "FAXX", "CELL" ] + "values": [ + "LETT", + "MAIL", + "PHON", + "FAXX", + "CELL" + ] + }, + "PersonIdentificationSchemeNameProprietary": { + "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 8, 1, 1, 0 ], + "type": "ENUMERATED", + "description": "Person identification scheme name proprietary values", + "values": [ + "DRLC", + "CPPT", + "ARNU", + "SSN", + "TXID", + "VISA", + "WPPT" + ] } }, "sequences": { @@ -268,20 +587,42 @@ "type": "SEQUENCE", "description": "Generic organization identification", "fields": { - "id": { "type": "Id", "optional": false }, - "schemeName": { "type": "OrganizationIdentificationSchemeNameChoice", "optional": true }, - "issuer": { "type": "Issuer", "optional": true } + "id": { + "type": "Id", + "optional": false + }, + "schemeName": { + "type": "OrganizationIdentificationSchemeNameChoice", + "optional": true + }, + "issuer": { + "type": "Issuer", + "optional": true + } }, - "field_order": ["id", "issuer", "schemeName"] + "field_order": [ + "id", + "issuer", + "schemeName" + ] }, "OrganizationIdentification": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 8, 0 ], "type": "SEQUENCE", "description": "Organization identification", "fields": { - "bic": { "type": "UTF8String", "optional": true }, - "lei": { "type": "UTF8String", "optional": true }, - "other": { "type": "SEQUENCE OF GenericOrganizationIdentification", "optional": true } + "bic": { + "type": "UTF8String", + "optional": true + }, + "lei": { + "type": "UTF8String", + "optional": true + }, + "other": { + "type": "SEQUENCE OF GenericOrganizationIdentification", + "optional": true + } } }, "GenericPersonIdentification": { @@ -289,19 +630,38 @@ "type": "SEQUENCE", "description": "Generic person identification", "fields": { - "id": { "type": "Id", "optional": false }, - "schemeName": { "type": "PersonIdentificationSchemeNameChoice", "optional": true }, - "issuer": { "type": "Issuer", "optional": true } + "id": { + "type": "Id", + "optional": false + }, + "schemeName": { + "type": "PersonIdentificationSchemeNameChoice", + "optional": true + }, + "issuer": { + "type": "Issuer", + "optional": true + } }, - "field_order": ["id", "issuer", "schemeName"] + "field_order": [ + "id", + "issuer", + "schemeName" + ] }, "PersonIdentification": { "oid": [ 1, 3, 6, 1, 4, 1, 62675, 1, 8, 1 ], "type": "SEQUENCE", "description": "Person identification", "fields": { - "dateAndPlaceOfBirth": { "type": "DateAndPlaceOfBirth", "optional": true }, - "other": { "type": "SEQUENCE OF GenericPersonIdentification", "optional": true } + "dateAndPlaceOfBirth": { + "type": "DateAndPlaceOfBirth", + "optional": true + }, + "other": { + "type": "SEQUENCE OF GenericPersonIdentification", + "optional": true + } } }, "OtherContact": { @@ -309,10 +669,19 @@ "type": "SEQUENCE", "description": "Other contact method", "fields": { - "id": { "type": "Id", "optional": true }, - "channelType": { "type": "UTF8String", "optional": false } + "id": { + "type": "Id", + "optional": true + }, + "channelType": { + "type": "UTF8String", + "optional": false + } }, - "field_order": ["channelType", "id"] + "field_order": [ + "channelType", + "id" + ] } } }, @@ -321,6 +690,62 @@ "oid": [ 1, 3, 6, 1, 4, 1, 62675, 0, 0 ], "description": "KYC attributes extension for X.509 certificates", "reference": "https://oid-base.com/get/1.3.6.1.4.1.62675.0.0" + }, + "DigestInfo": { + "description": "DigestInfo from RFC 3447", + "fields": { + "digestAlgorithm": { + "type": "OBJECT IDENTIFIER", + "optional": false + }, + "digest": { + "type": "OCTET STRING", + "optional": false + } + }, + "field_order": [ + "digestAlgorithm", + "digest" + ] + }, + "ExternalReference": { + "description": "External reference pointer", + "fields": { + "url": { + "type": "UTF8String", + "optional": false + }, + "contentType": { + "type": "UTF8String", + "optional": false + } + }, + "field_order": [ + "url", + "contentType" + ] + }, + "Reference": { + "description": "Reference", + "fields": { + "external": { + "type": "ExternalReference", + "optional": false + }, + "digest": { + "type": "DigestInfo", + "optional": false + }, + "encryptionAlgorithm": { + "type": "OBJECT IDENTIFIER", + "optional": false + } + }, + "field_order": [ + "external", + "digest", + "encryptionAlgorithm" + ] } } -} \ No newline at end of file +} diff --git a/keetanetwork-x509/src/utils.rs b/keetanetwork-x509/src/utils.rs index 783946b..408a64c 100644 --- a/keetanetwork-x509/src/utils.rs +++ b/keetanetwork-x509/src/utils.rs @@ -978,7 +978,7 @@ mod tests { assert_eq!(multi_pairs.len(), 7); // Verify each mapping - let expected_mappings = vec![ + let expected_mappings = [ ("commonName", "example.com"), ("organizationName", "Example Organization"), ("organizationalUnitName", "IT Department"),