def submit_domain_validation(client, regr, account, challenges_file, domain, log):
    # Get challenges for the domain.
    challg1 = get_challenges(client, regr, domain, challenges_file, log)
    challg = challg1.body

    if challg.status.name == "valid":
        # This is already valid. Return it immediately.
        return challg1
    elif challg.status.name != "pending":
        raise ChallengesUnknownStatus()

    # Look for a challenge combination that we can fulfill.
    for combination in challg.combinations:
        if len(combination) == 1:
            chg = challg.challenges[combination[0]]
            if isinstance(chg.chall, acme.challenges.SimpleHTTP):
                if chg.status.name != "pending":
                    # We can't submit twice. If this challenge is still pending
                    # but the overall challg object is not valid, then I'm not
                    # sure how to proceed.
                    raise ChallengesUnknownStatus()

                # Submit the SimpleHTTP challenge, raising NeedToInstallFile if
                # the conditions are not yet met.
                chg = answer_challenge_simplehttp(
                    domain,
                    chg.chall,
                    client,
                    account,
                    chg,
                    log)

                # The ChallengeResource probably comes back still pending because
                # it doesn't go THAT fast. Give it a moment, then poll.
                time.sleep(1)
                challg1, resp = client.poll(challg1)
                if challg1.body.status.name == "valid":
                    # It's valid now. That was fast.
                    return challg1

                # It's not valid. Tell the user they must want.
                retry_after = client.retry_after(resp, default=60)
                raise WaitABit(retry_after)

    raise NoChallengeMethodsSupported()
def submit_domain_validation(client, regr, account, challenges_file, domain,
                             validation_method, log):
    # Get challenges for the domain.
    challg1, resp = get_challenges(client, regr, domain, challenges_file, log)
    challg = challg1.body

    # If this challenge was just issued, we may not have a resp object yet
    # but may still need to raise a WaitABit exception.
    if resp:
        wait_until = client.retry_after(resp, default=60)
    else:
        wait_until = datetime.datetime.now() + datetime.timedelta(seconds=15)

    # The authorization object as a whole has a status.

    if challg.status.name == "valid":
        # This is already valid. Return it immediately.
        log("The challenges for %s have been accepted." % domain)
        return challg1

    elif challg.status.name == "invalid":
        # Challenge was rejected. The ACME server requested the
        # HTTP validation resource but got a 404, for instance.
        message = '; '.join(c.error.detail for c in challg.challenges
                            if c.status.name == "invalid")
        log("The %s challenge for %s failed: %s." %
            (validation_method, domain, message))
        raise ChallengeFailed(validation_method, domain, message, challg1.uri)

    elif challg.status.name not in ("pending", "processing"):
        # We can only respond to a challenge when its status is
        # pending. What do we do in the remaining case of "unknown"
        # status? ("revoked" is filtered out by get_challenges ---
        # we just request a new challenge in that case.)
        raise ChallengesUnknownStatus(challg.status.name)

    # Look for a challenge combination that we can fulfill.

    for combination in challg.combinations:
        if len(combination) == 1:
            chg = challg.challenges[combination[0]]
            if isinstance(chg.chall, acme.challenges.HTTP01) and isinstance(
                    validation_method, HTTPValidation):
                # The particular challenge within the big authorization object also
                # has a status. I'm not sure what the rules are for when the
                # statuses can be different.
                if chg.status.name == "processing":
                    # The challenge has been submitted and we must wait before proceeding,
                    # which is the next step after the for loop.
                    break

                elif chg.status.name == "valid":
                    # Looks like we already answered this challenge correctly.
                    # But the overall authorization object is not yet valid,
                    # so instruct the user to wait? That's the next step after
                    # the for loop.
                    break

                elif chg.status.name != "pending":
                    # We can only respond to a challenge when its status is
                    # pending. What do we do in the remaining cases?
                    # Other statuses are "unknown", "invalid" and "revoked".
                    raise ChallengesUnknownStatus(chg.status.name)

                # Submit the HTTP validation challenge, raising NeedToInstallFile if
                # the conditions are not yet met.
                chg = answer_challenge_http(domain, chg.chall,
                                            validation_method, client, account,
                                            chg, log)

                # We found a challenge combination we can submit for,
                # and we submitted it. The ChallengeResource probably
                # comes back still pending because it doesn't go THAT
                # fast. The next step after the for loop is to wait.
                break

    else:
        # We were unable to handle any challenge combination.
        raise NoChallengeMethodsSupported(
            "No supported challenge methods were offered for %s." % domain)

    # On success, or in other cases, wait.
    raise WaitABit(wait_until)
def submit_domain_validation(client, regr, account, challenges_file, domain, validation_method, log):
    # Get challenges for the domain.
    challg1, resp = get_challenges(client, regr, domain, challenges_file, log)
    challg = challg1.body

    # If this challenge was just issued, we may not have a resp object yet
    # but may still need to raise a WaitABit exception.
    if resp:
        wait_until = client.retry_after(resp, default=60)
    else:
        wait_until = datetime.datetime.now() + datetime.timedelta(seconds=15)

    # The authorization object as a whole has a status.

    if challg.status.name == "valid":
        # This is already valid. Return it immediately.
        log("The challenges for %s have been accepted." % domain)
        return challg1

    elif challg.status.name == "invalid":
        # Challenge was rejected. The ACME server requested the
        # HTTP validation resource but got a 404, for instance.
        message = '; '.join(c.error.detail for c in challg.challenges if c.status.name == "invalid")
        log("The %s challenge for %s failed: %s." % (validation_method, domain, message))
        raise ChallengeFailed(validation_method, domain, message, challg1.uri)

    elif challg.status.name not in ("pending", "processing"):
        # We can only respond to a challenge when its status is
        # pending. What do we do in the remaining case of "unknown"
        # status? ("revoked" is filtered out by get_challenges ---
        # we just request a new challenge in that case.)
        raise ChallengesUnknownStatus(challg.status.name)

    # Look for a challenge combination that we can fulfill.

    for combination in challg.combinations:
        if len(combination) == 1:
            chg = challg.challenges[combination[0]]
            if isinstance(chg.chall, acme.challenges.HTTP01) and isinstance(validation_method, HTTPValidation):
                # The particular challenge within the big authorization object also
                # has a status. I'm not sure what the rules are for when the
                # statuses can be different.
                if chg.status.name == "processing":
                    # The challenge has been submitted and we must wait before proceeding,
                    # which is the next step after the for loop.
                    break

                elif chg.status.name == "valid":
                    # Looks like we already answered this challenge correctly.
                    # But the overall authorization object is not yet valid,
                    # so instruct the user to wait? That's the next step after
                    # the for loop.
                    break

                elif chg.status.name != "pending":
                    # We can only respond to a challenge when its status is
                    # pending. What do we do in the remaining cases?
                    # Other statuses are "unknown", "invalid" and "revoked".
                    raise ChallengesUnknownStatus(chg.status.name)

                # Submit the HTTP validation challenge, raising NeedToInstallFile if
                # the conditions are not yet met.
                chg = answer_challenge_http(
                    domain,
                    chg.chall,
                    validation_method,
                    client,
                    account,
                    chg,
                    log)

                # We found a challenge combination we can submit for,
                # and we submitted it. The ChallengeResource probably
                # comes back still pending because it doesn't go THAT
                # fast. The next step after the for loop is to wait.
                break

    else:
        # We were unable to handle any challenge combination.
        raise NoChallengeMethodsSupported("No supported challenge methods were offered for %s." % domain)

    # On success, or in other cases, wait.
    raise WaitABit(wait_until)