Adjust original lambda to only filter based on ACI -> ACI identity key changes
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
Katherine 2026-03-11 15:31:00 -04:00 committed by GitHub
parent 3407212661
commit 563f41039c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 22 additions and 214 deletions

View File

@ -21,18 +21,12 @@ import java.util.Map;
import java.util.Objects;
record Account(
String number,
byte[] aci,
byte[] aciIdentityKey,
byte[] usernameHash) {
byte[] aciIdentityKey) {
@VisibleForTesting
static final String KEY_ACCOUNT_UUID = "U";
@VisibleForTesting
static final String ATTR_ACCOUNT_E164 = "P";
@VisibleForTesting
static final String ATTR_ACCOUNT_USERNAME_HASH = "N";
@VisibleForTesting
static final String ATTR_ACCOUNT_DATA = "D";
@Override
@ -42,10 +36,8 @@ record Account(
if (o == null || getClass() != o.getClass())
return false;
Account account = (Account) o;
return Objects.equals(number, account.number) &&
Arrays.equals(aci, account.aci) &&
Arrays.equals(aciIdentityKey, account.aciIdentityKey) &&
Arrays.equals(usernameHash, account.usernameHash);
return Arrays.equals(aci, account.aci) &&
Arrays.equals(aciIdentityKey, account.aciIdentityKey);
}
public record Pair(@Nullable Account prev, @Nullable Account next) implements KinesisRecord<Account> {
@ -72,7 +64,6 @@ record Account(
static Account fromItem(Map<String, AttributeValue> item) {
Preconditions.checkNotNull(item.get(KEY_ACCOUNT_UUID));
Preconditions.checkNotNull(item.get(ATTR_ACCOUNT_E164));
Preconditions.checkNotNull(item.get(ATTR_ACCOUNT_DATA));
final byte[] uuid = new byte[16];
item.get(KEY_ACCOUNT_UUID).getB().get(uuid);
@ -84,19 +75,7 @@ record Account(
} catch (IOException e) {
throw new UncheckedIOException("IOException from reading bytes array", e);
}
final String number = item.get(ATTR_ACCOUNT_E164).getS();
final byte[] usernameHash;
final AttributeValue usernameHashAv = item.get(ATTR_ACCOUNT_USERNAME_HASH);
if (usernameHashAv != null) {
usernameHash = new byte[32];
usernameHashAv.getB().asReadOnlyBuffer().get(usernameHash);
} else {
usernameHash = null;
}
return new Account(
number,
uuid,
identityKey,
usernameHash);
return new Account(uuid, identityKey);
}
}

View File

@ -12,16 +12,16 @@ import javax.annotation.Nullable;
import java.util.Map;
/**
* Filters DynamoDb record updates for the subset relevant to key transparency, outputting them to Kinesis
* Filters DynamoDb account updates for the subset relevant to key transparency, outputting them to Kinesis
*/
public class FilterKTUpdatesHandler extends AbstractUpdatesHandler<Account> {
public class FilterAciUpdatesHandler extends AbstractUpdatesHandler<Account> {
public FilterKTUpdatesHandler() {
public FilterAciUpdatesHandler() {
super();
}
@VisibleForTesting
FilterKTUpdatesHandler(final KinesisClient kinesisClient, final String kinesisOutputStream) {
FilterAciUpdatesHandler(final KinesisClient kinesisClient, final String kinesisOutputStream) {
super(kinesisClient, kinesisOutputStream);
}

View File

@ -27,7 +27,7 @@ import software.amazon.awssdk.services.kinesis.KinesisClient;
import software.amazon.awssdk.services.kinesis.model.PutRecordRequest;
// Modeled after https://aws.amazon.com/blogs/opensource/testing-aws-lambda-functions-written-in-java/
class FilterKTUpdatesHandlerTest {
class FilterAciUpdatesHandlerTest {
private static byte[] b64(String b) {
return Base64.getDecoder().decode(b);
@ -35,18 +35,14 @@ class FilterKTUpdatesHandlerTest {
static final byte[] PREV_ACI = b64("IiIiIiIiIiIiIiIiIiIiIg==");
static final byte[] PREV_ACI_KEY = b64("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
static final String PREV_NUM = "+111111111";
static final byte[] NEXT_ACI_KEY = b64("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
static final String NEXT_NUM = "+999999999";
static final byte[] PREV_USERHASH = b64("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
static final byte[] NEXT_USERHASH = b64("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
@ParameterizedTest
@MethodSource
void handleRequest(final String filename, final Account.Pair expected) {
final DynamodbEvent event = EventLoader.loadDynamoDbEvent(filename);
KinesisClient mockClient = mock(KinesisClient.class);
FilterKTUpdatesHandler handler = new FilterKTUpdatesHandler(mockClient, "mystream");
FilterAciUpdatesHandler handler = new FilterAciUpdatesHandler(mockClient, "mystream");
Context contextMock = mock(Context.class);
final StreamsEventResponse streamsEventResponse = handler.handleRequest(event, contextMock);
assertTrue(streamsEventResponse.getBatchItemFailures().isEmpty());
@ -61,42 +57,27 @@ class FilterKTUpdatesHandlerTest {
private static Stream<Arguments> handleRequest() {
return Stream.of(
Arguments.of(
"testevent_numberchange.json",
"aci/testevent_deletion.json",
new Account.Pair(
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, null),
new Account(NEXT_NUM, PREV_ACI, PREV_ACI_KEY, null))),
new Account(PREV_ACI, PREV_ACI_KEY),
null)),
Arguments.of(
"testevent_acikeychange.json",
new Account.Pair(
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, null),
new Account(PREV_NUM, PREV_ACI, NEXT_ACI_KEY, null))),
"aci/testevent_nochange.json", null),
Arguments.of(
"testevent_nochange.json", null),
Arguments.of(
"testevent_registration1.json",
"aci/testevent_registration1.json",
new Account.Pair(
null,
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, null))),
new Account(PREV_ACI, PREV_ACI_KEY))),
Arguments.of(
"testevent_registration2.json",
"aci/testevent_registration2.json",
new Account.Pair(
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, null),
new Account(PREV_NUM, PREV_ACI, NEXT_ACI_KEY, null))),
Arguments.of(
"testevent_userhashchange.json",
new Account.Pair(
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, PREV_USERHASH),
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, NEXT_USERHASH))),
Arguments.of(
"testevent_userhashadd.json",
new Account.Pair(
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, null),
new Account(PREV_NUM, PREV_ACI, PREV_ACI_KEY, NEXT_USERHASH))));
new Account(PREV_ACI, PREV_ACI_KEY),
new Account(PREV_ACI, NEXT_ACI_KEY))));
}
Account.Pair mapWithoutException(SdkBytes in) {
try {
return FilterKTUpdatesHandler.OBJECT_MAPPER.readValue(in.asInputStream(), Account.Pair.class);
return FilterAciUpdatesHandler.OBJECT_MAPPER.readValue(in.asInputStream(), Account.Pair.class);
} catch (IOException e) {
throw new RuntimeException("mapping", e);
}

View File

@ -3,7 +3,7 @@
{
"awsRegion": "us-east-1",
"eventID": "88888888-85b6-4a4b-a74e-bf4688888888",
"eventName": "MODIFY",
"eventName": "REMOVE",
"userIdentity": null,
"recordFormat": "application/json",
"tableName": "Signal_Accounts_Staging",
@ -25,17 +25,6 @@
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjpudWxsLCJyZXNlcnZlZFVzZXJuYW1lSGFzaCI6bnVsbCwiZGV2aWNlcyI6W10sImlkZW50aXR5S2V5IjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLCJiYWRnZXMiOltdLCJyZWdpc3RyYXRpb25Mb2NrIjpudWxsLCJyZWdpc3RyYXRpb25Mb2NrU2FsdCI6bnVsbCwidmVyc2lvbiI6MTMsInBuaSI6ImNjY2NjY2NjLWNjY2MtY2NjYy1kZGRkLWRkZGRkZGRkZGRkZCIsInBuaUlkZW50aXR5S2V5IjoiQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkIiLCJjcHYiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwidWFrIjoiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYj09IiwidXVhIjpmYWxzZSwiaW5DZHMiOnRydWV9Cg=="
}
},
"NewImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjpudWxsLCJyZXNlcnZlZFVzZXJuYW1lSGFzaCI6bnVsbCwiZGV2aWNlcyI6W10sImlkZW50aXR5S2V5IjoiWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWloiLCJiYWRnZXMiOltdLCJyZWdpc3RyYXRpb25Mb2NrIjpudWxsLCJyZWdpc3RyYXRpb25Mb2NrU2FsdCI6bnVsbCwidmVyc2lvbiI6MTMsInBuaSI6ImNjY2NjY2NjLWNjY2MtY2NjYy1kZGRkLWRkZGRkZGRkZGRkZCIsInBuaUlkZW50aXR5S2V5IjoiQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkIiLCJjcHYiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwidWFrIjoiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYj09IiwidXVhIjpmYWxzZSwiaW5DZHMiOnRydWV9Cg=="
}
},
"SizeBytes": 7001
},
"eventSource": "aws:dynamodb"

View File

@ -1,44 +0,0 @@
{
"Records": [
{
"awsRegion": "us-east-1",
"eventID": "88888888-85b6-4a4b-a74e-bf4688888888",
"eventName": "MODIFY",
"userIdentity": null,
"recordFormat": "application/json",
"tableName": "Signal_Accounts_Staging",
"dynamodb": {
"ApproximateCreationDateTime": 1630110857000,
"Keys": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
}
},
"OldImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjpudWxsLCJyZXNlcnZlZFVzZXJuYW1lSGFzaCI6bnVsbCwiZGV2aWNlcyI6W10sImlkZW50aXR5S2V5IjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLCJiYWRnZXMiOltdLCJyZWdpc3RyYXRpb25Mb2NrIjpudWxsLCJyZWdpc3RyYXRpb25Mb2NrU2FsdCI6bnVsbCwidmVyc2lvbiI6MTMsInBuaSI6ImNjY2NjY2NjLWNjY2MtY2NjYy1kZGRkLWRkZGRkZGRkZGRkZCIsInBuaUlkZW50aXR5S2V5IjoiQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkIiLCJjcHYiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwidWFrIjoiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYj09IiwidXVhIjpmYWxzZSwiaW5DZHMiOnRydWV9Cg=="
}
},
"NewImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+999999999"
},
"D": {
"B": "eyJudW1iZXIiOiIrOTk5OTk5OTk5IiwidXNlcm5hbWVIYXNoIjpudWxsLCJyZXNlcnZlZFVzZXJuYW1lSGFzaCI6bnVsbCwiZGV2aWNlcyI6W10sImlkZW50aXR5S2V5IjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLCJiYWRnZXMiOltdLCJyZWdpc3RyYXRpb25Mb2NrIjpudWxsLCJyZWdpc3RyYXRpb25Mb2NrU2FsdCI6bnVsbCwidmVyc2lvbiI6MTMsInBuaSI6ImNjY2NjY2NjLWNjY2MtY2NjYy1kZGRkLWRkZGRkZGRkZGRkZCIsInBuaUlkZW50aXR5S2V5IjoiQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkIiLCJjcHYiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwidWFrIjoiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYj09IiwidXVhIjpmYWxzZSwiaW5DZHMiOnRydWV9Cg=="
}
},
"SizeBytes": 7001
},
"eventSource": "aws:dynamodb"
}
]
}

View File

@ -1,47 +0,0 @@
{
"Records": [
{
"awsRegion": "us-east-1",
"eventID": "88888888-85b6-4a4b-a74e-bf4688888888",
"eventName": "MODIFY",
"userIdentity": null,
"recordFormat": "application/json",
"tableName": "Signal_Accounts_Staging",
"dynamodb": {
"ApproximateCreationDateTime": 1630110857000,
"Keys": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
}
},
"OldImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjpudWxsLCJyZXNlcnZlZFVzZXJuYW1lSGFzaCI6bnVsbCwiZGV2aWNlcyI6W10sImlkZW50aXR5S2V5IjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLCJiYWRnZXMiOltdLCJyZWdpc3RyYXRpb25Mb2NrIjpudWxsLCJyZWdpc3RyYXRpb25Mb2NrU2FsdCI6bnVsbCwidmVyc2lvbiI6MTMsInBuaSI6ImNjY2NjY2NjLWNjY2MtY2NjYy1kZGRkLWRkZGRkZGRkZGRkZCIsInBuaUlkZW50aXR5S2V5IjoiQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkIiLCJjcHYiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwidWFrIjoiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYj09IiwidXVhIjpmYWxzZSwiaW5DZHMiOnRydWV9Cg=="
}
},
"NewImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"N": {
"B": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE="
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjoiRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRSIsInJlc2VydmVkVXNlcm5hbWVIYXNoIjpudWxsLCJkZXZpY2VzIjpbXSwiaWRlbnRpdHlLZXkiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsImJhZGdlcyI6W10sInJlZ2lzdHJhdGlvbkxvY2siOm51bGwsInJlZ2lzdHJhdGlvbkxvY2tTYWx0IjpudWxsLCJ2ZXJzaW9uIjoxMywicG5pIjoiY2NjY2NjY2MtY2NjYy1jY2NjLWRkZGQtZGRkZGRkZGRkZGRkIiwicG5pSWRlbnRpdHlLZXkiOiJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQiIsImNwdiI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJ1YWsiOiJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiPT0iLCJ1dWEiOmZhbHNlLCJpbkNkcyI6dHJ1ZX0K"
}
},
"SizeBytes": 7001
},
"eventSource": "aws:dynamodb"
}
]
}

View File

@ -1,50 +0,0 @@
{
"Records": [
{
"awsRegion": "us-east-1",
"eventID": "88888888-85b6-4a4b-a74e-bf4688888888",
"eventName": "MODIFY",
"userIdentity": null,
"recordFormat": "application/json",
"tableName": "Signal_Accounts_Staging",
"dynamodb": {
"ApproximateCreationDateTime": 1630110857000,
"Keys": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
}
},
"OldImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"N": {
"B": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDA="
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjoiRERERERERERERERERERERERERERERERERERERERERERERERERERERERERCIsInJlc2VydmVkVXNlcm5hbWVIYXNoIjpudWxsLCJkZXZpY2VzIjpbXSwiaWRlbnRpdHlLZXkiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsImJhZGdlcyI6W10sInJlZ2lzdHJhdGlvbkxvY2siOm51bGwsInJlZ2lzdHJhdGlvbkxvY2tTYWx0IjpudWxsLCJ2ZXJzaW9uIjoxMywicG5pIjoiY2NjY2NjY2MtY2NjYy1jY2NjLWRkZGQtZGRkZGRkZGRkZGRkIiwicG5pSWRlbnRpdHlLZXkiOiJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQiIsImNwdiI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJ1YWsiOiJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiPT0iLCJ1dWEiOmZhbHNlLCJpbkNkcyI6dHJ1ZX0K"
}
},
"NewImage": {
"U": {
"B": "IiIiIiIiIiIiIiIiIiIiIg=="
},
"P": {
"S": "+111111111"
},
"N": {
"B": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE="
},
"D": {
"B": "eyJudW1iZXIiOiIrMTExMTExMTExIiwidXNlcm5hbWVIYXNoIjoiRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRSIsInJlc2VydmVkVXNlcm5hbWVIYXNoIjpudWxsLCJkZXZpY2VzIjpbXSwiaWRlbnRpdHlLZXkiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsImJhZGdlcyI6W10sInJlZ2lzdHJhdGlvbkxvY2siOm51bGwsInJlZ2lzdHJhdGlvbkxvY2tTYWx0IjpudWxsLCJ2ZXJzaW9uIjoxMywicG5pIjoiY2NjY2NjY2MtY2NjYy1jY2NjLWRkZGQtZGRkZGRkZGRkZGRkIiwicG5pSWRlbnRpdHlLZXkiOiJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQiIsImNwdiI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJ1YWsiOiJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiPT0iLCJ1dWEiOmZhbHNlLCJpbkNkcyI6dHJ1ZX0K"
}
},
"SizeBytes": 7001
},
"eventSource": "aws:dynamodb"
}
]
}