Selaa lähdekoodia

fix: normalize quoted DNS TXT values

AI-Co-Authored-By: Codex
chendeben 1 kuukausi sitten
vanhempi
sitoutus
977ce5d3ef
2 muutettua tiedostoa jossa 47 lisäystä ja 3 poistoa
  1. 9 3
      src/dns-providers.js
  2. 38 0
      test/dns-providers.test.js

+ 9 - 3
src/dns-providers.js

@@ -396,13 +396,19 @@ function pickExisting(desired, existing) {
 }
 
 function recordMatchesKind(desired, value) {
-  if (desired.key === 'spf') return /^v=spf1(?:\s|$)/i.test(String(value || '').trim());
-  if (desired.key === 'dmarc') return /^v=DMARC1(?:;|\s|$)/i.test(String(value || '').trim());
+  const normalized = normalizeValue(value);
+  if (desired.key === 'spf') return /^v=spf1(?:\s|$)/i.test(normalized);
+  if (desired.key === 'dmarc') return /^v=DMARC1(?:;|\s|$)/i.test(normalized);
   return normalizeValue(value) === normalizeValue(desired.value);
 }
 
 function normalizeValue(value) {
-  return String(value || '').replace(/\s+/g, ' ').trim();
+  return unquoteTxtValue(String(value || '').replace(/\s+/g, ' ').trim());
+}
+
+function unquoteTxtValue(value) {
+  if (value.length < 2 || !value.startsWith('"') || !value.endsWith('"')) return value;
+  return value.slice(1, -1).replace(/\\"/g, '"');
 }
 
 function sameDnsName(left, right) {

+ 38 - 0
test/dns-providers.test.js

@@ -87,6 +87,44 @@ test('cloudflare provider paginates exact record lookups before creating SPF rec
   assert.equal(calls.some((call) => call.method === 'POST'), false);
 });
 
+test('cloudflare provider matches quoted TXT SPF content returned by the API', async () => {
+  const calls = [];
+  globalThis.fetch = async (url, options = {}) => {
+    const urlText = String(url);
+    calls.push({ url: urlText, method: options.method || 'GET', body: options.body });
+    if (urlText.includes('/zones?name=example.com')) {
+      return json({ success: true, result: [{ id: 'zone-1', name: 'example.com' }] });
+    }
+    if (urlText.includes('/dns_records?')) {
+      return json({
+        success: true,
+        result: [
+          { id: 'spf-1', type: 'TXT', name: 'example.com', content: '"v=spf1 include:spf.mailjet.com +include:spf.97admin.com -all"' },
+          { id: 'spf-2', type: 'TXT', name: 'example.com', content: '"v=spf1 include:spf.mailjet.com include:spf.97admin.com ip4:192.0.2.10 a:in.example.com -all"' }
+        ],
+        result_info: { page: 1, total_pages: 1 }
+      });
+    }
+    return json({ success: true, result: { id: 'ok' } });
+  };
+
+  const result = await applyDnsSetup(domainFixture(), cloudflareCredential(), {
+    records: [
+      {
+        key: 'spf',
+        host: 'example.com',
+        type: 'TXT',
+        value: 'v=spf1 include:spf.mailjet.com include:spf.97admin.com ip4:192.0.2.10 a:in.example.com -all'
+      }
+    ]
+  });
+
+  assert.equal(result.ok, true);
+  assert.ok(calls.some((call) => call.method === 'PUT' && call.url.includes('/dns_records/spf-1')));
+  assert.ok(calls.some((call) => call.method === 'DELETE' && call.url.includes('/dns_records/spf-2')));
+  assert.equal(calls.some((call) => call.method === 'POST'), false);
+});
+
 test('aliyun provider signs and sends create/update record actions', async () => {
   const actions = [];
   globalThis.fetch = async (url) => {