resolve static method

Future<AppleResolvedSigningAssets> resolve({
  1. required AppleSigningCredentials credentials,
  2. required Set<String> bundleIds,
  3. required AppStoreConnectApi client,
  4. ProcessRunner processRunner = const SystemProcessRunner(),
  5. Directory? temporaryRoot,
  6. DateTime currentTime()?,
})

Finds or creates profiles through Apple's supported provisioning API.

Implementation

static Future<AppleResolvedSigningAssets> resolve({
  required AppleSigningCredentials credentials,
  required Set<String> bundleIds,
  required AppStoreConnectApi client,
  ProcessRunner processRunner = const SystemProcessRunner(),
  Directory? temporaryRoot,
  DateTime Function()? currentTime,
}) async {
  SmfError.check(
    bundleIds.isNotEmpty,
    'No signed Apple bundle identifiers were discovered.',
    SmfErrorCode.appleSigningTargetsNotFound,
  );
  final now = (currentTime ?? DateTime.now)().toUtc();
  final validAfter = now.add(_minimumSigningValidity);
  final certificateDer = await _certificateDer(
    credentials,
    processRunner: processRunner,
    temporaryRoot: temporaryRoot,
  );
  final certificates = await client.listSigningCertificates();
  final contentMatches = certificates.where((certificate) {
    List<int> content;
    try {
      content = base64Decode(
        certificate.certificateContent.replaceAll(RegExp(r'\s'), ''),
      );
    } on FormatException catch (error) {
      throw SmfError(
        'Apple returned malformed distribution-certificate content.',
        SmfErrorCode.appStoreConnectResponse,
        cause: error,
      );
    }
    return _bytesEqual(certificateDer, content);
  }).toList();
  SmfError.check(
    contentMatches.length == 1,
    contentMatches.isEmpty
        ? 'The supplied .p12 certificate is not registered with this Apple '
              'developer team.'
        : 'Apple returned the supplied .p12 certificate more than once.',
    SmfErrorCode.appleCertificateNotFound,
  );
  final certificate = contentMatches.single;
  SmfError.check(
    _distributionCertificateTypes.contains(certificate.certificateType),
    'The supplied .p12 is ${certificate.certificateType}, not an Apple '
    'Distribution certificate.',
    SmfErrorCode.appleCertificateTypeMismatch,
  );
  SmfError.check(
    certificate.isActivated && certificate.expirationDate.isAfter(validAfter),
    'The supplied Apple Distribution certificate is inactive, expired, or '
    'expires within 24 hours.',
    SmfErrorCode.appleCertificateInvalid,
  );

  final registered = await client.listIosBundleIds();
  final bundleResources = <String, AppleBundleIdentifierDto>{};
  for (final bundleId in bundleIds) {
    final matches = registered
        .where(
          (resource) => resource.platform == 'IOS' && resource.identifier == bundleId,
        )
        .toList();
    SmfError.check(
      matches.length == 1,
      matches.isEmpty
          ? 'No registered iOS App ID matches $bundleId.'
          : 'Apple returned more than one iOS App ID for $bundleId.',
      SmfErrorCode.appleBundleIdNotFound,
    );
    bundleResources[bundleId] = matches.single;
  }

  final knownProfiles = List<AppleProvisioningProfileDto>.of(
    await client.listAppStoreProfiles(),
  );
  final knownNames = knownProfiles.map((profile) => profile.name).toSet();
  final encodedProfiles = <String, String>{};
  final sortedBundleResources = bundleResources.entries.toList()
    ..sort((left, right) => left.key.compareTo(right.key));
  for (final bundleEntry in sortedBundleResources) {
    final bundleId = bundleEntry.key;
    final bundleResource = bundleEntry.value;
    var profile = _bestProfile(
      knownProfiles,
      bundleResource,
      certificate,
      validAfter,
    );
    if (profile == null) {
      final profileName = _availableProfileName(
        bundleId,
        certificate.serialNumber,
        knownNames,
      );
      knownNames.add(profileName);
      profile = await _createOrRecoverProfile(
        client: client,
        name: profileName,
        bundleId: bundleResource,
        certificate: certificate,
        validAfter: validAfter,
      );
      knownProfiles.add(profile);
    }
    _validateProfile(profile, bundleResource, certificate, validAfter);
    encodedProfiles[bundleId] = _normalizedBase64Profile(
      profile.profileContent,
      bundleId,
    );
  }

  return AppleResolvedSigningAssets(
    credentials: credentials,
    profilesByBundleId: Map<String, String>.unmodifiable(encodedProfiles),
  );
}