feat: add vehicle key derivation

This commit is contained in:
lingniu
2026-06-29 12:53:08 +08:00
parent 4feb1ec829
commit aed023043c
2 changed files with 88 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
package com.lingniu.ingest.facts;
import com.lingniu.ingest.api.ProtocolId;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
public final class VehicleKey {
private VehicleKey() {
}
public static String derive(ProtocolId protocol, String vin, String phone, String rawIdentitySeed) {
if (protocol == null) {
throw new IllegalArgumentException("protocol must not be null");
}
String normalizedVin = clean(vin);
if (!normalizedVin.isBlank()) {
return normalizedVin;
}
String normalizedPhone = clean(phone);
if (protocol == ProtocolId.JT808 && !normalizedPhone.isBlank()) {
return "jt808:" + normalizedPhone;
}
String seed = clean(rawIdentitySeed);
if (seed.isBlank()) {
seed = protocol.name();
}
return "unknown:" + protocol.name() + ":" + sha256(seed).substring(0, 16);
}
private static String clean(String value) {
return value == null ? "" : value.trim();
}
private static String sha256(String value) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return HexFormat.of().formatHex(digest.digest(value.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("SHA-256 is unavailable", e);
}
}
}

View File

@@ -0,0 +1,42 @@
package com.lingniu.ingest.facts;
import com.lingniu.ingest.api.ProtocolId;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class VehicleKeyTest {
@Test
void usesVinForGb32960() {
assertThat(VehicleKey.derive(ProtocolId.GB32960, " LB9A32A20P0LS1257 ", "", "abc"))
.isEqualTo("LB9A32A20P0LS1257");
}
@Test
void usesResolvedVinForJt808WhenPresent() {
assertThat(VehicleKey.derive(ProtocolId.JT808, "VIN001", "013912345678", "abc"))
.isEqualTo("VIN001");
}
@Test
void usesPhoneForJt808WhenVinIsMissing() {
assertThat(VehicleKey.derive(ProtocolId.JT808, "", "013912345678", "abc"))
.isEqualTo("jt808:013912345678");
}
@Test
void usesStableUnknownHashWhenVehicleIdentifiersAreMissing() {
assertThat(VehicleKey.derive(ProtocolId.JT808, "", "", "abc"))
.isEqualTo(VehicleKey.derive(ProtocolId.JT808, null, null, "abc"))
.startsWith("unknown:JT808:");
}
@Test
void rejectsMissingProtocol() {
assertThatThrownBy(() -> VehicleKey.derive(null, "VIN001", "", "abc"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("protocol");
}
}