doACMEChallenge method

Future<List<String>> doACMEChallenge(
  1. String cn,
  2. List<String> contacts,
  3. String accountPrivateKeyPem,
  4. String accountPublicKeyPem,
  5. String domainCSR,
)

Performs an ACME challenge. Default to HTTP-1.

  • cn is the domain to request a certificate.
  • contacts is the list of domain contacts, usually emails.
  • accountPrivateKeyPem is the account private key in PEM format.
  • accountPublicKeyPem is the account public key in PEM format.
  • domainCSR is the domain Certificate Signing Request in PEM format.

Used by requestCertificate.

Implementation

Future<List<String>> doACMEChallenge(
  String cn,
  List<String> contacts,
  final String accountPrivateKeyPem,
  final String accountPublicKeyPem,
  final String domainCSR,
) async {
  var contactsWithMethod = contacts
      .map((e) => !e.startsWith(_regexpContactMethodPrefix) && e.contains('@')
          ? 'mailto:$e'
          : e)
      .toList();

  _logInfo(
      'apiBaseURL: $apiBaseURL ; cn: $cn ; contacts: $contactsWithMethod');

  var client = AcmeClient(
    apiBaseURL,
    accountPrivateKeyPem,
    accountPublicKeyPem,
    true,
    contactsWithMethod,
  );

  await _initializeClient(client, cn);

  var order = Order(identifiers: [Identifiers(type: 'dns', value: cn)]);
  _logInfo('Order for $cn: ${order.toJson()}');

  var newOrder = await client.order(order);

  _logInfo('Fetching authorization data for order...');

  var auth = await client.getAuthorization(newOrder!);
  if (auth == null || auth.isEmpty) {
    throw StateError("Can't get Authorization");
  }

  var mainAuth = auth.first;
  var challengeData = mainAuth.getHttpDcvData();

  _challengesTokens[cn] = challengeData.fileContent;

  _logInfo('Self test challenge... ${challengeData.toJson()}');

  var selfTestOK = await _selfChallengeTest(client, challengeData);
  if (!selfTestOK) {
    throw StateError("Self HTTP test not OK!");
  }

  var challenge =
      mainAuth.challenges!.firstWhere((e) => e.type == VALIDATION_HTTP);

  _logInfo('Validating challenge: ${challenge.toJson()}');
  var valid = await client.validate(challenge);

  if (!valid) {
    throw StateError("Challenge not valid!");
  }

  _logInfo('Authorization successful!');

  await Future.delayed(Duration(seconds: 1));

  var ready = await client.isReady(newOrder);
  if (!ready) {
    throw StateError("Order not ready!");
  }

  _logInfo('Finalizing order...');
  var persistent = await client.finalizeOrder(newOrder, domainCSR);

  if (persistent == null) {
    throw StateError("Error finalizing order!");
  }

  _logInfo('Getting certificates...');
  var certs = await client.getCertificate(persistent);

  _challengesTokens.remove(cn);

  if (certs == null || certs.isEmpty) {
    throw StateError("Error getting certificates!");
  }

  _logInfo('Certificates:\n>> ${certs.join('\n>> ')}');

  return certs;
}