check method

Future<DVApiKeyCheck> check(
  1. String presented, {
  2. String? tenant,
})

Checks presented, with the reason when it does not authenticate.

tenant is the tenant the request resolved to. When it is not given and the call runs inside a DV.Tenants.withTenant scope, that scope's tenant is the one the key must belong to.

Implementation

Future<DVApiKeyCheck> check(String presented, {String? tenant}) async {
  final String? id = _idOf(presented);
  if (id == null) {
    return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
  }
  final DVRecord? record = await _keys.read(id);
  if (record == null) {
    DVSecretHash.matches(_absentHash, presented);
    return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
  }
  if (!DVSecretHash.matches('${record.values['secret_hash']}', presented)) {
    return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
  }
  final DVApiKey key = _keyFrom(record);
  final DateTime now = _now();
  if (key.revokedAt != null) {
    return DVApiKeyCheck.failed(DVApiKeyFailure.revoked, key: key);
  }
  final DateTime? expiry = key.expiresAt;
  if (expiry != null && !now.isBefore(expiry)) {
    if (key.rotatedTo == null) {
      return DVApiKeyCheck.failed(DVApiKeyFailure.expired, key: key);
    }
    _log.info(
      'DV-APIKEY-003: rotation overlap expired; ${key.prefix} no longer '
      'authenticates, its replacement is ${keyPrefix}${key.rotatedTo}.',
    );
    return DVApiKeyCheck.failed(
      DVApiKeyFailure.expired,
      key: key,
      code: 'DV-APIKEY-003',
    );
  }
  final String? requested =
      tenant ?? (DVTenants.hasScope ? const DVTenants().currentTenant : null);
  if (requested != null && requested != key.tenant) {
    return DVApiKeyCheck.failed(DVApiKeyFailure.wrongTenant, key: key);
  }
  return DVApiKeyCheck.valid(key, principalFor(key));
}