feat: получение записей домена

This commit is contained in:
2025-07-18 03:27:54 +03:00
parent 66d22f6f7c
commit 22b4846ef9
7 changed files with 281 additions and 3 deletions

View File

@@ -0,0 +1,49 @@
package ru.di9.ihc;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class DomainRecord {
private final int id;
private final boolean readOnly;
private final RecordType type;
private String name;
private String content;
private Integer priority;
public DomainRecord(int id, boolean readOnly, String name, RecordType type, String content, Integer priority) {
this.id = id;
this.readOnly = readOnly;
this.name = name;
this.type = type;
this.content = content;
this.priority = priority;
}
public void setName(String name) {
if (readOnly) {
throw new RuntimeException("READ ONLY RECORD");
}
this.name = name;
}
public void setContent(String content) {
if (readOnly) {
throw new RuntimeException("READ ONLY RECORD");
}
this.content = content;
}
public void setPriority(Integer priority) {
if (readOnly) {
throw new RuntimeException("READ ONLY RECORD");
}
if (!RecordType.MX.equals(type) && !RecordType.SRV.equals(type)) {
throw new RuntimeException("NOT SUPPORT SET PRIORITY FOR " + type.name() + " RECORD");
}
this.priority = priority;
}
}

View File

@@ -0,0 +1,22 @@
package ru.di9.ihc;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public record DomainRecordsResponse(Data data) {
@JsonIgnoreProperties(ignoreUnknown = true)
public record Data(List<Record> records) {
}
public record Record(
int id,
boolean readOnly,
String name,
String type,
String content,
Integer prio
) {
}
}

View File

@@ -16,9 +16,7 @@ import org.jsoup.select.Elements;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
public class IhcClient {
private final String baseUrl;
@@ -90,4 +88,45 @@ public class IhcClient {
throw new RuntimeException(e);
}
}
public List<DomainRecord> getDomainRecords(int domainId) {
if (!isAuth) {
throw new RuntimeException("IS NOT AUTH");
}
HttpPost httpPost = new HttpPost(URI.create("%s/dnsZone/records".formatted(baseUrl)));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpPost.setHeader("Referer", "%s/dnsZone/index/%d".formatted(baseUrl, domainId));
httpPost.setEntity(new UrlEncodedFormEntity(List.of(
new BasicNameValuePair("id", String.valueOf(domainId))
)));
try {
return httpClient.execute(httpPost, resp -> {
if (resp.getCode() != 200) {
return Collections.emptyList();
}
DomainRecordsResponse response = mapper.readValue(resp.getEntity().getContent(), DomainRecordsResponse.class);
List<DomainRecord> list = new ArrayList<>();
for (DomainRecordsResponse.Record rec : response.data().records()) {
list.add(new DomainRecord(
rec.id(),
rec.readOnly(),
rec.name(),
RecordType.valueOf(rec.type()),
rec.content(),
rec.prio()
));
}
list.sort(Comparator.comparingInt(DomainRecord::getId));
return list;
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,13 @@
package ru.di9.ihc;
public enum RecordType {
SOA,
A,
AAAA,
CNAME,
MX,
TXT,
SRV,
NS,
CAA
}

View File

@@ -0,0 +1,79 @@
package ru.di9.ihc;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static org.junit.jupiter.api.Assertions.*;
class GetDomainRecordsTest {
static int port;
static WireMockServer wireMockServer;
@BeforeAll
static void beforeAll() {
port = RandomUtils.nextInt(9000, 9999);
wireMockServer = new WireMockServer(port);
wireMockServer.start();
}
@AfterAll
static void afterAll() {
wireMockServer.stop();
}
@AfterEach
void after() {
wireMockServer.resetAll();
}
@Test
void test() throws IOException {
wireMockServer.stubFor(post("/j_spring_security_check?ajax=true")
.willReturn(WireMock.okJson("""
{"redirect":{"url":"/"},"alert":{"type":"none","message":""}}""")));
wireMockServer.stubFor(get("/dnsZone/list")
.willReturn(WireMock.ok(IOUtils.resourceToString("/ihc-dns.html", StandardCharsets.UTF_8))
.withHeader("Content-Type", "text/html")));
wireMockServer.stubFor(post("/dnsZone/records")
.willReturn(WireMock.okJson(IOUtils.resourceToString("/ihc-domain.json", StandardCharsets.UTF_8))));
var ihc = new IhcClient("http://localhost:%d".formatted(port));
ihc.auth("user1", "passwd1");
Integer domainId = ihc.getDomains().getFirst().getValue();
List<DomainRecord> domainRecords = ihc.getDomainRecords(domainId);
assertEquals(7, domainRecords.size());
DomainRecord record1 = domainRecords.getFirst();
assertEquals(7000001, record1.getId());
assertTrue(record1.isReadOnly());
assertEquals(RecordType.SOA, record1.getType());
assertEquals("", record1.getName());
assertEquals("ns1.ihc.ru. info.ihc.ru. 2014120801 10800 3600 604800 3600", record1.getContent());
assertNull(record1.getPriority());
assertThrows(RuntimeException.class, () -> record1.setName("xx"));
DomainRecord record2 = domainRecords.get(4);
assertEquals(7000005, record2.getId());
assertFalse(record2.isReadOnly());
assertEquals(RecordType.MX, record2.getType());
assertEquals("", record2.getName());
assertEquals("mx.yandex.ru", record2.getContent());
assertEquals(10, record2.getPriority());
assertDoesNotThrow(() -> record2.setName("xx"));
}
}

View File

@@ -0,0 +1,72 @@
{
"alert": {
"type": "none",
"message": ""
},
"data": {
"errors": [],
"messages": [],
"domain": {
"name": "example-1.ru",
"id": 111111
},
"records": [
{
"readOnly": true,
"id": 7000001,
"name": "",
"type": "SOA",
"content": "ns1.ihc.ru. info.ihc.ru. 2014120801 10800 3600 604800 3600",
"prio": null
},
{
"readOnly": true,
"id": 7000002,
"name": "",
"type": "NS",
"content": "ns1.ihc.ru",
"prio": null
},
{
"readOnly": true,
"id": 7000003,
"name": "",
"type": "NS",
"content": "ns2.ihc.ru",
"prio": null
},
{
"readOnly": false,
"id": 7000004,
"name": "yamail-XXXXXXXXXXXX",
"type": "CNAME",
"content": "mail.yandex.ru",
"prio": null
},
{
"readOnly": false,
"id": 7000005,
"name": "",
"type": "MX",
"content": "mx.yandex.ru",
"prio": 10
},
{
"readOnly": false,
"id": 7000006,
"name": "",
"type": "A",
"content": "127.0.0.1",
"prio": null
},
{
"readOnly": false,
"id": 7000007,
"name": "_acme-challenge",
"type": "TXT",
"content": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"prio": null
}
]
}
}