Skip to content

HTTP challenge with DNS fallback #100

@oalders

Description

@oalders

In dealing with wildcard domains, it's handy to do the HTTP challenges first and then fall back to DNS for any names (ie wildcards) which failed the HTTP challenge. I could not find a way to do this with the current API, so I have been doing the following. I realize that this is bad for poking at the internals, but as a stopgap it does the trick. Am I missing something?

Please note: I can't really take credit for this. It was quite late at night and I had claude.ai generate most of it in order to rest my brain.

package Crypt::LE::Batch;

use strict;
use warnings;

use parent 'Crypt::LE';

use Crypt::LE qw( OK );

sub accept_challenge {
    my ( $self, $cb, $params, $type ) = @_;

    # For non-dns challenges, use parent behavior
    return $self->SUPER::accept_challenge( $cb, $params, $type )
        unless $type eq 'dns';

    # Store original state
    my $full_challenges        = $self->{challenges};
    my $full_domains           = $self->{loaded_domains};
    my $full_active_challenges = $self->{active_challenges};

    # Filter to only keep wildcard domains
    my $wildcard_challenges = {};
    my @wildcard_domains;
    foreach my $domain (@$full_domains) {
        next unless $domain =~ /^\*\./;    # only wildcards
        if ( exists $full_challenges->{$domain} ) {
            $wildcard_challenges->{$domain} = $full_challenges->{$domain};
            push @wildcard_domains, $domain;
        }
    }

    # Temporarily replace with filtered set
    $self->{challenges}        = $wildcard_challenges;
    $self->{loaded_domains}    = \@wildcard_domains;
    $self->{active_challenges} = {};    # Start fresh for DNS challenges

    # Let parent handle the actual validation with filtered domains
    my $status = $self->SUPER::accept_challenge( $cb, $params, $type );

    if ( $status == OK ) {

        # Merge the active challenges back
        $self->{active_challenges} = {
            %{ $full_active_challenges || {} },
            %{ $self->{active_challenges} || {} }
        };
    }

    # Restore remaining original state
    $self->{challenges}     = $full_challenges;
    $self->{loaded_domains} = $full_domains;

    return $status;
}

# Override verify_challenge to only verify wildcards for DNS
sub verify_challenge {
    my ( $self, $cb, $params, $type ) = @_;

    return $self->SUPER::verify_challenge( $cb, $params, $type )
        unless $type && $type eq 'dns';

    # Store original state
    my $full_domains = $self->{loaded_domains};

    # Filter to only verify wildcard domains
    my @wildcard_domains = grep { /^\*\./ } @$full_domains;
    $self->{loaded_domains} = \@wildcard_domains;

    # Let parent handle verification
    my $status = $self->SUPER::verify_challenge( $cb, $params, $type );

    # Restore original state
    $self->{loaded_domains} = $full_domains;

    return $status;
}

1;

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions