ClientService.java
package se.jobtechdev.personaldatagateway.api.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import se.jobtechdev.personaldatagateway.api.generated.entities.ClientEntity;
import se.jobtechdev.personaldatagateway.api.generated.entities.ClientKeyResetEntity;
import se.jobtechdev.personaldatagateway.api.generated.entities.OrganizationEntity;
import se.jobtechdev.personaldatagateway.api.generated.model.ClientKey;
import se.jobtechdev.personaldatagateway.api.repository.ClientKeyResetRepository;
import se.jobtechdev.personaldatagateway.api.repository.ClientRepository;
import se.jobtechdev.personaldatagateway.api.util.KeyProvider;
import se.jobtechdev.personaldatagateway.api.util.TimeProvider;
import se.jobtechdev.personaldatagateway.api.util.UuidProvider;
import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.UUID;
import static se.jobtechdev.personaldatagateway.api.util.MessageDigestProvider.sha256;
@Component
public class ClientService {
private final ClientRepository clientRepository;
private final ClientKeyResetRepository clientKeyResetRepository;
@SuppressWarnings("unused")
@Autowired
public ClientService(
ClientRepository clientRepository, ClientKeyResetRepository clientKeyResetRepository) {
this.clientRepository = clientRepository;
this.clientKeyResetRepository = clientKeyResetRepository;
}
public Page<ClientEntity> getClients(Pageable pageable) {
return clientRepository.findAll(pageable);
}
public Optional<ClientEntity> getClientById(UUID clientId) {
return clientRepository.findById(clientId);
}
public Optional<ClientEntity> getClientByKeyHash(byte[] apiKeyHash) {
return clientRepository.findByKeyHash(apiKeyHash);
}
@Transactional
public ClientEntity createClient(
OrganizationEntity organization, String name, String role, byte[] clientKey) {
final var clientId = UuidProvider.uuid();
final var now = TimeProvider.now();
final var client = new ClientEntity(clientId, organization, sha256(clientKey), name, role, now, now);
return clientRepository.save(client);
}
@Transactional
public ClientEntity saveClient(ClientEntity client) {
return clientRepository.save(client);
}
@Transactional
public void delete(ClientEntity client) {
clientRepository.delete(client);
}
public Page<ClientKeyResetEntity> getAllClientKeyResetsByClientId(ClientEntity client, Pageable pageable) {
return clientKeyResetRepository.findAllByClientEntity(client, pageable);
}
@Transactional
public ClientKeyResetEntity keyReset(ClientEntity client) {
final var now = ZonedDateTime.now();
final var code = KeyProvider.randomCode(6);
// reset the hash
final var hash = new byte[256];
client.setKeyHash(hash);
client.setUpdated(now);
clientRepository.save(client);
final var clientKeyReset = new ClientKeyResetEntity(UUID.randomUUID(), client, now, now, code, null);
return clientKeyResetRepository.save(clientKeyReset);
}
public Optional<ClientKeyResetEntity> getKeyReset(ClientEntity client, String code) {
return clientKeyResetRepository.findByClientEntityAndCode(client, code);
}
@Transactional
public ClientKey key(ClientEntity client, ClientKeyResetEntity clientKeyReset) {
final var now = ZonedDateTime.now();
final var key = KeyProvider.randomBytes(32);
final var keyHash = sha256(key);
final var keyResetCode = KeyProvider.randomCode(6);
client.setKeyHash(keyHash);
client.setKeyResetCode(keyResetCode);
client.setUpdated(now);
clientRepository.save(client);
final var base64EncodedKey = KeyProvider.b64EncodedKey(key);
clientKeyReset.setAccessed(now);
clientKeyReset.setUpdated(now);
clientKeyResetRepository.save(clientKeyReset);
return new ClientKey(client.getId(), base64EncodedKey, keyResetCode);
}
}