Beispiel #1
0
// Completes a given challenge, polling it until it is complete. Can be
// cancelled using ctx.
//
// dnsName is the hostname which is being authorized. webPaths and priorKeyFunc
// are passed to responders.
//
// The return value indicates whether the whole authorization has been invalidated
// (set to "failed" status) as a result of an error. In this case a new authorization
// must be created.
func CompleteChallenge(c *acmeapi.Client, ch *acmeapi.Challenge, dnsName string, ccfg responder.ChallengeConfig, ctx context.Context) (invalidated bool, err error) {
	log.Debugf("attempting challenge type %s", ch.Type)

	var certs [][]byte
	for _, c := range ch.Certs {
		certs = append(certs, c)
	}

	r, err := responder.New(responder.Config{
		Type:                   ch.Type,
		Token:                  ch.Token,
		AccountKey:             c.AccountKey,
		Hostname:               dnsName,
		AcceptableCertificates: certs,
		ChallengeConfig:        ccfg,
	})

	if err != nil {
		log.Debuge(err, "challenge instantiation failed")
		return false, err
	}

	err = r.Start()
	if err != nil {
		log.Debuge(err, "challenge start failed")
		return false, err
	}

	defer r.Stop()

	err = c.RespondToChallenge(ch, r.Validation(), r.ValidationSigningKey(), ctx)
	if err != nil {
		return false /* ??? */, err
	}

	b := denet.Backoff{
		InitialDelay: 5 * time.Second,
		MaxDelay:     30 * time.Second,
	}

	for {
		log.Debug("waiting to poll challenge")
		select {
		case <-ctx.Done():
			return true, ctx.Err()
		case <-r.RequestDetectedChan():
			log.Debug("request detected")
		case <-time.After(b.NextDelay()):
		}

		log.Debug("querying challenge status")
		err := c.WaitLoadChallenge(ch, ctx)
		if err != nil {
			return false, err
		}

		if ch.Status.Final() {
			log.Debug("challenge now in final state")
			break
		}
	}

	if ch.Status != "valid" {
		return true, fmt.Errorf("challenge failed with status %#v", ch.Status)
	}

	return false, nil
}