DVPlayStoreAdapter.fromSecrets constructor

DVPlayStoreAdapter.fromSecrets(
  1. DVPlayStoreConfig config, {
  2. DVBillingFetch? fetch,
  3. DateTime clock()?,
  4. DVSecrets secrets = const DVSecrets(),
})

Builds the adapter from a project's declaration and DV Secrets.

The credential is read from PLAY_SERVICE_ACCOUNT_JSON, the service account file as Google issues it, or from PLAY_SERVICE_ACCOUNT_EMAIL and PLAY_SERVICE_ACCOUNT_KEY when the two are kept apart. Push settings left out of config are read from PLAY_PUSH_AUDIENCE and PLAY_PUSH_SERVICE_ACCOUNT; with neither, every push is refused.

Nothing read from a secret is repeated in an error: a message gets pasted into tickets and chat, and a private key must not be in them.

Implementation

factory DVPlayStoreAdapter.fromSecrets(
  DVPlayStoreConfig config, {
  DVBillingFetch? fetch,
  DateTime Function()? clock,
  DVSecrets secrets = const DVSecrets(),
}) {
  String? email;
  String? key;
  final String? file = secrets.maybeGet('PLAY_SERVICE_ACCOUNT_JSON');
  if (file != null && file.trim().isNotEmpty) {
    final Object? decoded;
    try {
      decoded = jsonDecode(file);
    } on Object {
      throw StateError('PLAY_SERVICE_ACCOUNT_JSON is not a JSON file');
    }
    if (decoded is! Map ||
        (decoded['type'] != null && decoded['type'] != 'service_account')) {
      throw StateError(
          'PLAY_SERVICE_ACCOUNT_JSON is not a service account key file');
    }
    final Object? fileEmail = decoded['client_email'];
    final Object? fileKey = decoded['private_key'];
    email = fileEmail is String ? fileEmail : null;
    key = fileKey is String ? fileKey : null;
  } else {
    email = secrets.maybeGet('PLAY_SERVICE_ACCOUNT_EMAIL');
    key = secrets.maybeGet('PLAY_SERVICE_ACCOUNT_KEY');
  }
  if (email == null || email.isEmpty || key == null || key.isEmpty) {
    throw StateError(
        'Google Play has no service account: set PLAY_SERVICE_ACCOUNT_JSON '
        '(the key file) or PLAY_SERVICE_ACCOUNT_EMAIL and '
        'PLAY_SERVICE_ACCOUNT_KEY in DV Secrets');
  }
  try {
    return DVPlayStoreAdapter(
      packageName: config.packageName,
      serviceAccountEmail: email,
      serviceAccountPrivateKeyPem: key,
      fetch: fetch,
      clock: clock,
      pushAudience:
          config.pushAudience ?? secrets.maybeGet('PLAY_PUSH_AUDIENCE'),
      pushServiceAccountEmail: config.pushServiceAccount ??
          secrets.maybeGet('PLAY_PUSH_SERVICE_ACCOUNT'),
    );
  } on ArgumentError {
    throw StateError('the Google Play service account key is not readable');
  }
}