diff --git a/docs/epp.md b/docs/epp.md index 71cb50d..4b9694e 100644 --- a/docs/epp.md +++ b/docs/epp.md @@ -462,6 +462,23 @@ Each command section below includes real-world XML request and response samples ``` +**Response with Identica in database:** + +```xml +... + + + 1234567890 + 2 + 2025-07-02T10:34:00.000Z + admin42|api|Validated via national ID system + + +... +``` + #### 2.4. Contact Update **Standard request:** @@ -538,6 +555,9 @@ Each command section below includes real-world XML request and response samples xmlns:identica="https://namingo.org/epp/identica-1.0" xsi:schemaLocation="https://namingo.org/epp/identica-1.0 identica-1.0.xsd"> 1234567890 + 2 + 2025-07-02T10:34:00.000Z + admin42|api|Validated via national ID system client-20241128-12345 @@ -1189,20 +1209,6 @@ Each command section below includes real-world XML request and response samples ``` -**Response with Identica in database:** - -```xml -... - - - 1234567890 - - -... -``` - #### 4.4. Domain Update **Request:** diff --git a/epp/src/EppWriter.php b/epp/src/EppWriter.php index b5bd301..9da5a09 100644 --- a/epp/src/EppWriter.php +++ b/epp/src/EppWriter.php @@ -611,6 +611,22 @@ class EppWriter { $writer->writeAttribute('type', $resp['nin_type']); $writer->text($resp['nin']); $writer->endElement(); // End of 'identica:nin' + + // Validation status + if (isset($resp['validation'])) { + $writer->writeElement('identica:status', $resp['validation']); + } + + // Validation timestamp + if (!empty($resp['validation_stamp'])) { + $stamp = new \DateTime($resp['validation_stamp']); + $writer->writeElement('identica:date', $stamp->format('Y-m-d\TH:i:s.v\Z')); + } + + // Validation log + if (!empty($resp['validation_log'])) { + $writer->writeElement('identica:details', $resp['validation_log']); + } $writer->endElement(); // End of 'identica:infData' $writer->endElement(); // End of 'extension' diff --git a/epp/src/epp-info.php b/epp/src/epp-info.php index 64192dd..d4beb1f 100644 --- a/epp/src/epp-info.php +++ b/epp/src/epp-info.php @@ -19,7 +19,7 @@ function processContactInfo($conn, $db, $xml, $clid, $trans) { // Optimized single query $stmt = $db->prepare(" SELECT c.id, c.identifier, c.voice, c.fax, c.email, c.clid, c.crid, c.crdate, c.upid, c.lastupdate, - c.disclose_voice, c.disclose_fax, c.disclose_email, + c.disclose_voice, c.disclose_fax, c.disclose_email, c.nin, c.nin_type, c.validation, c.validation_stamp, c.validation_log, p.type AS postal_type, p.name, p.org, p.street1, p.street2, p.street3, p.city, p.sp, p.pc, p.cc, p.disclose_name_int, p.disclose_name_loc, p.disclose_org_int, p.disclose_org_loc, p.disclose_addr_int, p.disclose_addr_loc, @@ -120,6 +120,23 @@ function processContactInfo($conn, $db, $xml, $clid, $trans) { ]; } + if (!empty($contactRow['nin']) && !empty($contactRow['nin_type'])) { + $response['nin'] = $contactRow['nin']; + $response['nin_type'] = $contactRow['nin_type']; + + if (!is_null($contactRow['validation'])) { + $response['validation'] = $contactRow['validation']; + } + + if (!is_null($contactRow['validation_stamp'])) { + $response['validation_stamp'] = $contactRow['validation_stamp']; + } + + if (!empty($contactRow['validation_log'])) { + $response['validation_log'] = $contactRow['validation_log']; + } + } + $epp = new EPP\EppWriter(); $xml = $epp->epp_writer($response); updateTransaction($db, 'info', 'contact', $contactID, 1000, 'Command completed successfully', $svTRID, $xml, $trans); diff --git a/epp/src/epp-update.php b/epp/src/epp-update.php index 94c9c0d..a2435c1 100644 --- a/epp/src/epp-update.php +++ b/epp/src/epp-update.php @@ -431,6 +431,13 @@ function processContactUpdate($conn, $db, $xml, $clid, $database_type, $trans) { if ($identica_update) { $nin = (string)$identica_update->xpath('//identica:nin[1]')[0]; $nin_type = (string)$identica_update->xpath('//identica:nin/@type[1]')[0]; + $status = $identica_update->xpath('//identica:status[1]'); + $statusDate = $identica_update->xpath('//identica:date[1]'); + $statusDetails = $identica_update->xpath('//identica:details[1]'); + + $validation = isset($status[0]) ? (string)$status[0] : null; + $validation_stamp = isset($statusDate[0]) ? (string)$statusDate[0] : null; + $validation_log = isset($statusDetails[0]) ? (string)$statusDetails[0] : null; if (!preg_match('/\d/', $nin)) { sendEppError($conn, $db, 2005, 'NIN should contain one or more numbers', $clTRID, $trans); @@ -441,6 +448,21 @@ function processContactUpdate($conn, $db, $xml, $clid, $database_type, $trans) { sendEppError($conn, $db, 2005, 'NIN Type should contain personal or business', $clTRID, $trans); return; } + + if ($validation !== null && !in_array($validation, ['0','1','2','3','4'])) { + sendEppError($conn, $db, 2005, 'Validation status must be 0–4', $clTRID, $trans); + return; + } + + if ($validation_stamp !== null && !preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/', $validation_stamp)) { + sendEppError($conn, $db, 2005, 'Invalid status date format. Use ISO 8601 format like 2025-07-02T12:00:00.000Z', $clTRID, $trans); + return; + } + + if ($validation_log !== null && strlen($validation_log) > 255) { + sendEppError($conn, $db, 2005, 'Validation log exceeds maximum allowed length (255 characters)', $clTRID, $trans); + return; + } } if (!empty($contactRem)) { @@ -703,7 +725,11 @@ function processContactUpdate($conn, $db, $xml, $clid, $database_type, $trans) { } if ($identica_update) { - $query = "UPDATE contact SET nin = ?, nin_type = ?, upid = ?, lastupdate = CURRENT_TIMESTAMP(3) WHERE id = ?"; + $query = " + UPDATE contact + SET nin = ?, nin_type = ?, validation = ?, validation_stamp = ?, validation_log = ?, upid = ?, lastupdate = CURRENT_TIMESTAMP(3) + WHERE id = ? + "; $stmt = $db->prepare($query); if (!$stmt) { @@ -714,6 +740,9 @@ function processContactUpdate($conn, $db, $xml, $clid, $database_type, $trans) { $result = $stmt->execute([ $nin ?: null, $nin_type ?: null, + $validation, + $validation_stamp ?: null, + $validation_log ?: null, $clid, $contact_id ]);