Migration Payload.batch_id should be int32
tc287 opened this issue · comments
a2c0a3f changes a bunch of protobuf fields from int32 to uint32; I assume this was in due to the discussion around google/google-authenticator-android#118 (comment) (batch_id sometimes being negative).
I believe this is incorrect! After figuring out how to generate batched migration codes (an Android-only feature), the first batch_id I see is 18446744073509271282 (0xfffffffff40ff6f2), which indicates that the type is a negative int32 ("if you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes long"). This shows up as "%2F%2F%2F%2F" in the otpauth-migration URL, making it easy to spot.
(I agree that uint32 would have been a more sensible type, but it is not the type they used.)
If you want to dig deeper, you can look at the generated code's dynamicMethod(): For BUILD_MESSAGE_INFO, it returns a RawMessageInfo which encodes a bunch more information from the source proto (including the "FieldType"). But given that batch_id is int32, it seems reasonable to assume that integer fields are int32 by default.
You may be right, but I could not deduce it with certainly now.
Here are encoded message info definitions. I see some patterns here, but I'm not quite sure, how to decode 'em:
Main Payload
message:
01 05 00 01 01 05 05 00 01 00
01 1b # otpParameters_
02 e1 80 84 00 # version_ (u?int32) → 4: int32
03 e1 80 84 01 # batchSize_ (u?int32) → 4: int32
04 e1 80 84 02 # batchIndex_ (u?int32) → 4: int32
05 e1 80 84 03 # batchId_ (u?int32) → 4: int32
And embedded OtpParams
message:
01 07 00 01 01 07 07 00 00 00
01 e1 80 8a 00 # secret_ (bytes)
02 e1 80 88 01 # name_ (string)
03 e1 80 88 02 # issuer_ (string)
04 e1 80 8c 03 # algorithm_ (enum)
05 e1 80 8c 04 # digits_ (enum)
06 e1 80 8c 05 # type_ (enum)
07 e1 80 83 06 # counter_ (u?int64) → 3: uint64
Would love to hear, if you know more.
The encoding is described in RawMessageInfo.java and encodes integers using 1-3 UTF-16 "chars". Fortunately, most numbers are small enough to be encoded in a single char, so the only thing you need to worry about is U+0000 encoding as c0 80
due to "modified UTF-8" (depending on the tool you use to view the strings).
In the above, e1 80 84
represents 0x1004, e1 80 83
represents 0x1003, etc. This is the "field type with extra bits"; the lower 8 bits are the field type from FieldType.java: 4 is int32, 3 is uint64, 8 is string, 0xA (10) is bytes, 0xC (12) is enum.
Thanks! That helped.