Add more missing stuff

This commit is contained in:
Fang-Pen Lin
2025-11-20 20:45:19 -08:00
parent 551e9b4476
commit d72c63667e
3 changed files with 139 additions and 2 deletions

View File

@@ -14,6 +14,7 @@ import { decryptAppConnection } from "@app/services/app-connection/app-connectio
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
import { TAwsConnection } from "@app/services/app-connection/aws/aws-connection-types";
import { TCloudflareConnection } from "@app/services/app-connection/cloudflare/cloudflare-connection-types";
import { TDNSMadeEasyConnection } from "@app/services/app-connection/dns-made-easy/dns-made-easy-connection-types";
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
import { TCertificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal";
@@ -43,8 +44,8 @@ import {
TUpdateAcmeCertificateAuthorityDTO
} from "./acme-certificate-authority-types";
import { cloudflareDeleteTxtRecord, cloudflareInsertTxtRecord } from "./dns-providers/cloudflare";
import { dnsMadeEasyDeleteTxtRecord, dnsMadeEasyInsertTxtRecord } from "./dns-providers/dns-made-easy";
import { route53DeleteTxtRecord, route53InsertTxtRecord } from "./dns-providers/route54";
import { TDNSMadeEasyConnection } from "@app/services/app-connection/dns-made-easy/dns-made-easy-connection-types";
type TAcmeCertificateAuthorityFnsDeps = {
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById">;
@@ -308,6 +309,7 @@ export const orderCertificate = async (
recordName,
recordValue
);
break;
}
default: {
throw new Error(`Unsupported DNS provider: ${acmeCa.configuration.dnsProviderConfig.provider as string}`);

View File

@@ -0,0 +1,129 @@
import axios from "axios";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { crypto } from "@app/lib/crypto/cryptography";
import { TDNSMadeEasyConnection } from "@app/services/app-connection/dns-made-easy/dns-made-easy-connection-types";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
const getDNSMadeEasyUrl = (path: string) => {
const appCfg = getConfig();
return `${appCfg.DNS_MADE_EASY_SANDBOX_ENABLED ? IntegrationUrls.DNS_MADE_EASY_SANDBOX_API_URL : IntegrationUrls.DNS_MADE_EASY_API_URL}${path}`;
};
const makeDNSMadeEasyAuthHeaders = (
apiKey: string,
secretKey: string,
currentDate: Date = new Date()
): Record<string, string> => {
// Format date as "Day, DD Mon YYYY HH:MM:SS GMT" (e.g., "Mon, 01 Jan 2024 12:00:00 GMT")
const requestDate = currentDate.toUTCString();
// Generate HMAC-SHA1 signature
const hmac = crypto.nativeCrypto.createHmac("sha1", secretKey);
hmac.update(requestDate);
const hmacSignature = hmac.digest("hex");
return {
"x-dnsme-apiKey": apiKey,
"x-dnsme-hmac": hmacSignature,
"x-dnsme-requestDate": requestDate
};
};
export const dnsMadeEasyInsertTxtRecord = async (
connection: TDNSMadeEasyConnection,
hostedZoneId: string,
domain: string,
value: string
) => {
const {
credentials: { apiKey, secretKey }
} = connection;
try {
await request.post(
getDNSMadeEasyUrl(`/V2.0/dns/managed/${encodeURIComponent(hostedZoneId)}/records`),
{
type: "TXT",
name: domain,
value,
ttl: 60
},
{
headers: {
...makeDNSMadeEasyAuthHeaders(apiKey, secretKey),
"Content-Type": "application/json",
Accept: "application/json"
}
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
const errorMessage =
(error.response?.data as { error?: string[] | string })?.error?.[0] ||
(error.response?.data as { error?: string[] | string })?.error ||
error.message ||
"Unknown error";
throw new Error(typeof errorMessage === "string" ? errorMessage : String(errorMessage));
}
throw error;
}
};
export const dnsMadeEasyDeleteTxtRecord = async (
connection: TDNSMadeEasyConnection,
hostedZoneId: string,
domain: string,
value: string
) => {
const {
credentials: { apiKey, secretKey }
} = connection;
try {
// First, list records to find the record ID
const listRecordsResponse = await request.get<{
data: Array<{ id: number; type: string; name: string; value: string }>;
}>(getDNSMadeEasyUrl(`/V2.0/dns/managed/${encodeURIComponent(hostedZoneId)}/records`), {
headers: {
...makeDNSMadeEasyAuthHeaders(apiKey, secretKey),
Accept: "application/json"
},
params: {
type: "TXT",
recordName: domain
}
});
const dnsRecords = listRecordsResponse.data?.data;
if (Array.isArray(dnsRecords) && dnsRecords.length > 0) {
const recordToDelete = dnsRecords.find(
(record) => record.type === "TXT" && record.name === domain && record.value === value
);
if (recordToDelete) {
await request.delete(
getDNSMadeEasyUrl(`/V2.0/dns/managed/${encodeURIComponent(hostedZoneId)}/records/${recordToDelete.id}`),
{
headers: {
...makeDNSMadeEasyAuthHeaders(apiKey, secretKey),
Accept: "application/json"
}
}
);
}
}
} catch (error) {
if (axios.isAxiosError(error)) {
const errorMessage =
(error.response?.data as { error?: string[] | string })?.error?.[0] ||
(error.response?.data as { error?: string[] | string })?.error ||
error.message ||
"Unknown error";
throw new Error(typeof errorMessage === "string" ? errorMessage : String(errorMessage));
}
throw error;
}
};

View File

@@ -184,6 +184,10 @@ export type TRedisConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Redis;
};
export type TDNSMadeEasyConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.DNSMadeEasy;
};
export type TAppConnectionOption =
| TAwsConnectionOption
| TGitHubConnectionOption
@@ -225,7 +229,8 @@ export type TAppConnectionOption =
| TOktaConnectionOption
| TAzureAdCsConnectionOption
| TLaravelForgeConnectionOption
| TChefConnectionOption;
| TChefConnectionOption
| TDNSMadeEasyConnectionOption;
export type TAppConnectionOptionMap = {
[AppConnection.AWS]: TAwsConnectionOption;
@@ -257,6 +262,7 @@ export type TAppConnectionOptionMap = {
[AppConnection.Flyio]: TFlyioConnectionOption;
[AppConnection.GitLab]: TGitlabConnectionOption;
[AppConnection.Cloudflare]: TCloudflareConnectionOption;
[AppConnection.DNSMadeEasy]: TDNSMadeEasyConnectionOption;
[AppConnection.Bitbucket]: TBitbucketConnectionOption;
[AppConnection.Zabbix]: TZabbixConnectionOption;
[AppConnection.Railway]: TRailwayConnectionOption;