Commit efcb26319392

Vincent Demeester <vincent@sbr.pm>
2026-05-07 10:57:05
feat: added ATProto handle TXT record and TXT support in DNS script
Added _atproto.vincent.demeester.fr TXT record for handle verification. Updated Gandi DNS script to process TXT records with multi-value support.
1 parent a555ad1
Changed files (2)
systems
common
services
tools
systems/common/services/dns/demeester.fr.nix
@@ -58,7 +58,7 @@ with dns.lib.combinators;
     # ATProto PDS
     pds.A = [ "46.224.100.116" ];
 
-    # ATProto handle verification (placeholder - update DID after account creation)
-    # "_atproto.vincent".TXT = [ "did=did:plc:PLACEHOLDER" ];
+    # ATProto handle verification
+    vincent.subdomains._atproto.TXT = [ "did=did:plc:q4ernihrsd4rdu4sedrm3vwa" ];
   };
 }
tools/update-gandi-dns.sh
@@ -266,6 +266,93 @@ update_domain() {
         done <<< "$CNAME_RECORDS"
     fi
 
+    # Process TXT records
+    # Group TXT records by name since a single name can have multiple values
+    if [[ -n "$TXT_RECORDS" ]]; then
+        declare -A TXT_BY_NAME
+        while IFS= read -r line; do
+            FULL_NAME=$(echo "$line" | awk '{print $1}')
+
+            if [[ "$FULL_NAME" == "$DOMAIN." ]]; then
+                NAME="@"
+            else
+                NAME="${FULL_NAME%.$DOMAIN.}"
+            fi
+
+            # Extract TXT value (everything after TXT, keeping quotes)
+            VALUE=$(echo "$line" | sed 's/.*TXT[[:space:]]*//' | sed 's/^"//;s/"$//')
+
+            if [[ -n "${TXT_BY_NAME[$NAME]+_}" ]]; then
+                TXT_BY_NAME[$NAME]="${TXT_BY_NAME[$NAME]}|||$VALUE"
+            else
+                TXT_BY_NAME[$NAME]="$VALUE"
+            fi
+        done <<< "$TXT_RECORDS"
+
+        for NAME in "${!TXT_BY_NAME[@]}"; do
+            IFS='|||' read -ra VALUES <<< "${TXT_BY_NAME[$NAME]}"
+            # Filter empty values from split
+            CLEAN_VALUES=()
+            for v in "${VALUES[@]}"; do
+                [[ -n "$v" ]] && CLEAN_VALUES+=("$v")
+            done
+
+            echo -e "${BLUE}Processing: ${RESET}$NAME.$DOMAIN TXT (${#CLEAN_VALUES[@]} values)"
+
+            if [[ "$DRY_RUN" == "true" ]]; then
+                echo -e "  ${CYAN}[DRY RUN] Would update/create TXT record${RESET}"
+                for v in "${CLEAN_VALUES[@]}"; do
+                    echo -e "    ${CYAN}$v${RESET}"
+                done
+                UPDATED=$((UPDATED + 1))
+            else
+                # Build JSON array of values
+                JSON_VALUES=$(printf '%s\n' "${CLEAN_VALUES[@]}" | jq -R . | jq -s .)
+
+                # Get current values
+                CURRENT_TXT=$(echo "$CURRENT_RECORDS" | jq -r \
+                  --arg name "$NAME" \
+                  '.[] | select(.rrset_name == $name and .rrset_type == "TXT") | .rrset_values | sort | join(",")' \
+                  2>/dev/null || echo "")
+
+                NEW_TXT=$(echo "$JSON_VALUES" | jq -r 'sort | join(",")' 2>/dev/null || echo "")
+
+                if [[ "$CURRENT_TXT" == "$NEW_TXT" ]]; then
+                    echo -e "  ${GREEN}โœ“ Record unchanged, skipping${RESET}"
+                    SKIPPED=$((SKIPPED + 1))
+                else
+                    if [[ -z "$CURRENT_TXT" ]]; then
+                        echo -e "  ${YELLOW}Creating new TXT record...${RESET}"
+                    else
+                        echo -e "  ${YELLOW}Updating TXT record...${RESET}"
+                    fi
+
+                    RESPONSE=$(curl -s -w "\n%{http_code}" \
+                      -X PUT \
+                      -H "Authorization: Bearer $GANDIV5_PERSONAL_TOKEN" \
+                      -H "Content-Type: application/json" \
+                      -d "{\"rrset_values\": $JSON_VALUES, \"rrset_ttl\": 10800}" \
+                      "$API_URL/$NAME/TXT")
+
+                    HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
+                    BODY=$(echo "$RESPONSE" | sed '$d')
+
+                    if [[ "$HTTP_CODE" == "201" ]] || [[ "$HTTP_CODE" == "200" ]]; then
+                        echo -e "  ${GREEN}โœ“ TXT record updated successfully${RESET}"
+                        UPDATED=$((UPDATED + 1))
+                    else
+                        echo -e "  ${RED}โœ— Failed to update TXT record (HTTP $HTTP_CODE)${RESET}"
+                        echo -e "  ${RED}Response: $BODY${RESET}"
+                        FAILED=$((FAILED + 1))
+                    fi
+                fi
+            fi
+
+            echo
+        done
+        unset TXT_BY_NAME
+    fi
+
     # Remove stale A records from Gandi that are no longer in Nix config
     echo -e "${BOLD}${BLUE}Checking for stale A records to remove...${RESET}"
     echo