-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(storage) Add V4 signing support #4692
Changes from 3 commits
d3b121c
71846ac
ab931d8
d4fb299
4e30cdc
ddc786c
0d7f114
8e8ca08
d48e8c4
7d23539
d3acaf1
85a0dc2
c36cbc3
15737c5
69d4a17
964af50
9986c97
24bf576
7d18fde
c5fd070
98c31b9
e0d0f32
9709087
ed25ac4
63c42ad
ed7e8c4
836d7d5
022d5ba
5534b2f
c104811
9fcb46f
6d35976
54e722c
b0a992e
7a836e4
0e152ec
6785005
8958a7d
b0d677d
d94d805
b249848
aa837fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -626,7 +626,7 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio | |
|
||
long expiration = | ||
isV4 | ||
? duration | ||
? unit.toMillis(duration) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. V4 expects seconds as the unit of expiration. IIUC this is converting it to milliseconds. |
||
: TimeUnit.SECONDS.convert( | ||
getOptions().getClock().millisTime() + unit.toMillis(duration), | ||
TimeUnit.MILLISECONDS); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,6 +85,11 @@ | |
import com.google.common.collect.Lists; | ||
import com.google.common.io.BaseEncoding; | ||
import com.google.common.io.ByteStreams; | ||
import com.google.gson.Gson; | ||
import com.google.gson.GsonBuilder; | ||
import com.google.gson.JsonArray; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonObject; | ||
import com.google.iam.v1.Binding; | ||
import com.google.iam.v1.IAMPolicyGrpc; | ||
import com.google.iam.v1.SetIamPolicyRequest; | ||
|
@@ -104,7 +109,10 @@ | |
import java.net.URL; | ||
import java.net.URLConnection; | ||
import java.nio.ByteBuffer; | ||
import java.nio.file.Files; | ||
import java.nio.file.Paths; | ||
import java.security.Key; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
|
@@ -168,10 +176,15 @@ public static void beforeClass() throws IOException { | |
remoteStorageHelper = RemoteStorageHelper.create(); | ||
storage = remoteStorageHelper.getOptions().getService(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming you're adding integration tests (I think you mentioned it), but I want to make sure they are still added before this is merged. |
||
storage.create( BucketInfo.newBuilder(BUCKET) .setLocation("us") .setLifecycleRules( | ||
ImmutableList.of( new LifecycleRule( LifecycleAction.newDeleteAction(), | ||
LifecycleCondition.newBuilder().setAge(1).build()))) .build()); | ||
|
||
storage.create( | ||
BucketInfo.newBuilder(BUCKET) | ||
.setLocation("us") | ||
.setLifecycleRules( | ||
ImmutableList.of( | ||
new LifecycleRule( | ||
LifecycleAction.newDeleteAction(), | ||
LifecycleCondition.newBuilder().setAge(1).build()))) | ||
.build()); | ||
|
||
// Prepare KMS KeyRing for CMEK tests | ||
prepareKmsKeys(); | ||
|
@@ -1841,34 +1854,80 @@ public void testGetSignedUrl() throws IOException { | |
} | ||
} | ||
|
||
public class TestCase { | ||
String description; | ||
String bucket; | ||
String object; | ||
String method; | ||
String expiration; | ||
String timestamp; | ||
String expectedUrl; | ||
JsonObject headers; | ||
|
||
public String toString() { | ||
return description; | ||
} | ||
} | ||
|
||
@Test | ||
//TODO rewrite this to load JSON conformance tests instead | ||
public void testV4UrlSigning() throws IOException { | ||
public void testV4UrlSigning() throws Exception { | ||
Storage dummyAccountStorage = | ||
remoteStorageHelper | ||
.getOptions() | ||
.toBuilder() | ||
.setClock( | ||
new FakeClock(TimeUnit.NANOSECONDS.convert(1549040400000L, TimeUnit.MILLISECONDS))) | ||
.setCredentials( | ||
ServiceAccountCredentials.fromStream( | ||
new FileInputStream( | ||
new File("src/test/resources/URLSignerV4TestAccount.json")))) | ||
.build() | ||
.getService(); | ||
String bucket = "test-bucket"; | ||
String object = "test-object"; | ||
|
||
BlobInfo blob = BlobInfo.newBuilder(bucket, object).build(); | ||
Gson gson = new GsonBuilder().create(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JesseLovelace this looks good. I think it should it be in a separate test file outside of integration tests given these tests aren't making a request to the GCS service. |
||
|
||
String testCaseJson = | ||
new String(Files.readAllBytes(Paths.get("src/test/resources/URLSignerV4TestData.json"))); | ||
|
||
JsonArray testCases = gson.fromJson(testCaseJson, JsonArray.class); | ||
|
||
for (JsonElement testCaseElement : testCases) { | ||
TestCase testCase = gson.fromJson(testCaseElement, TestCase.class); | ||
|
||
dummyAccountStorage = | ||
dummyAccountStorage | ||
.getOptions() | ||
.toBuilder() | ||
.setClock( | ||
new FakeClock( | ||
TimeUnit.NANOSECONDS.convert( | ||
new SimpleDateFormat("yyyyMMdd'T'hhmmss'Z'") | ||
.parse(testCase.timestamp) | ||
.getTime(), | ||
TimeUnit.MILLISECONDS))) | ||
.build() | ||
.getService(); | ||
|
||
BlobInfo blob = BlobInfo.newBuilder(testCase.bucket, testCase.object).build(); | ||
|
||
Map<String, String> headers = new HashMap<>(); | ||
if (testCase.headers != null) { | ||
for (Map.Entry<String, JsonElement> entry : testCase.headers.entrySet()) { | ||
JsonArray value = entry.getValue().getAsJsonArray(); | ||
headers.put(entry.getKey(), value.get(0).getAsString()); | ||
} | ||
} | ||
|
||
assertEquals( | ||
"https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74", | ||
dummyAccountStorage.signUrl( | ||
blob, | ||
10, | ||
TimeUnit.SECONDS, | ||
Storage.SignUrlOption.httpMethod(HttpMethod.GET), | ||
Storage.SignUrlOption.withV4Signature()).toString()); | ||
assertEquals( | ||
testCase.expectedUrl, | ||
dummyAccountStorage | ||
.signUrl( | ||
blob, | ||
Long.valueOf(testCase.expiration), | ||
TimeUnit.MILLISECONDS, | ||
Storage.SignUrlOption.httpMethod(HttpMethod.valueOf(testCase.method)), | ||
Storage.SignUrlOption.withExtHeaders(headers), | ||
Storage.SignUrlOption.withV4Signature()) | ||
.toString()); | ||
} | ||
} | ||
|
||
@Test | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Assumed constant for all tests: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Conformance tests were updated and should be updated here as well. |
||
// - email: test-iam-credentials@dummy-project-id.iam.gserviceaccount.com | ||
// - project: dummy-project-id | ||
[ | ||
{ | ||
"description": "Simple GET", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74" | ||
}, | ||
|
||
{ | ||
"description": "Simple PUT", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"method": "PUT", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=8adff1d4285739e31aa68e73767a46bc5511fde377497dbe08481bf5ceb34e29cc9a59921748d8ec3dd4085b7e9b7772a952afedfcdaecb3ae8352275b8b7c867f204e3db85076220a3127a8a9589302fc1181eae13b9b7fe41109ec8cdc93c1e8bac2d7a0cc32a109ca02d06957211326563ab3d3e678a0ba296e298b5fc5e14593c99d444c94724cc4be97015dbff1dca377b508fa0cb7169195de98d0e4ac96c42b918d28c8d92d33e1bd125ce0fb3cd7ad2c45dae65c22628378f6584971b8bf3945b26f2611eb651e9b6a8648970c1ecf386bb71327b082e7296c4e1ee2fc0bdd8983da80af375c817fb1ad491d0bc22c0f51dba0d66e2cffbc90803e47" | ||
}, | ||
|
||
{ | ||
"description": "POST for resumable uploads", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"method": "POST", | ||
"expiration": 10, | ||
"headers": { | ||
"x-goog-resumable": [ "start" ] | ||
}, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bx-goog-resumable&X-Goog-Signature=4a6d39b23343cedf4c30782aed4b384001828c79ffa3a080a481ea01a640dea0a0ceb58d67a12cef3b243c3f036bb3799c6ee88e8db3eaf7d0bdd4b70a228d0736e07eaa1ee076aff5c6ce09dff1f1f03a0d8ead0d2893408dd3604fdabff553aa6d7af2da67cdba6790006a70240f96717b98f1a6ccb24f00940749599be7ef72aaa5358db63ddd54b2de9e2d6d6a586eac4fe25f36d86fc6ab150418e9c6fa01b732cded226c6d62fc95b72473a4cc55a8257482583fe66d9ab6ede909eb41516a8690946c3e87b0f2052eb0e97e012a14b2f721c42e6e19b8a1cd5658ea36264f10b9b1ada66b8ed5bf7ed7d1708377ac6e5fe608ae361fb594d2e5b24c54" | ||
}, | ||
|
||
{ | ||
"description": "Vary expiration and timestamp", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"method": "GET", | ||
"expiration": 20, | ||
"timestamp": "20190301T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190301%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190301T090000Z&X-Goog-Expires=20&X-Goog-SignedHeaders=host&X-Goog-Signature=9669ed5b10664dc594c758296580662912cf4bcc5a4ba0b6bf055bcbf6f34eed7bdad664f534962174a924741a0c273a4f67bc1847cef20192a6beab44223bd9d4fbbd749c407b79997598c30f82ddc269ff47ec09fa3afe74e00616d438df0d96a7d8ad0adacfad1dc3286f864d924fe919fb0dce45d3d975c5afe8e13af2db9cc37ba77835f92f7669b61e94c6d562196c1274529e76cfff1564cc2cad7d5387dc8e12f7a5dfd925685fe92c30b43709eee29fa2f66067472cee5423d1a3a4182fe8cea75c9329d181dc6acad7c393cd04f8bf5bc0515127d8ebd65d80c08e19ad03316053ea60033fd1b1fd85a69c576415da3bf0a3718d9ea6d03e0d66f0" | ||
}, | ||
|
||
{ | ||
"description": "Vary bucket and object", | ||
"bucket": "test-bucket2", | ||
"object": "test-object2", | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket2/test-object2?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=36e3d58dfd3ec1d2dd2f24b5ee372a71e811ffaa2162a2b871d26728d0354270bc116face87127532969c4a3967ed05b7309af741e19c7202f3167aa8c2ac420b61417d6451442bb91d7c822cd17be8783f01e05372769c88913561d27e6660dd8259f0081a71f831be6c50283626cbf04494ac10c394b29bb3bce74ab91548f58a37118a452693cf0483d77561fc9cac8f1765d2c724994cca46a83517a10157ee0347a233a2aaeae6e6ab5e204ff8fc5f54f90a3efdb8301d9fff5475d58cd05b181affd657f48203f4fb133c3a3d355b8eefbd10d5a0a5fd70d06e9515460ad74e22334b2cba4b29cae4f6f285cdb92d8f3126d7a1479ca3bdb69c207d860" | ||
}, | ||
|
||
{ | ||
"description": "Simple headers", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"headers": { | ||
"foo": [ "foo-value" ], | ||
"BAR": [ "BAR-value" ] | ||
}, | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=bar%3Bfoo%3Bhost&X-Goog-Signature=68ecd3b008328ed30d91e2fe37444ed7b9b03f28ed4424555b5161980531ef87db1c3a5bc0265aad5640af30f96014c94fb2dba7479c41bfe1c020eb90c0c6d387d4dd09d4a5df8b60ea50eb6b01cdd786a1e37020f5f95eb8f9b6cd3f65a1f8a8a65c9fcb61ea662959efd9cd73b683f8d8804ef4d6d9b2852419b013368842731359d7f9e6d1139032ceca75d5e67cee5fd0192ea2125e5f2955d38d3d50cf116f3a52e6a62de77f6207f5b95aaa1d7d0f8a46de89ea72e7ea30f21286318d7eba0142232b0deb3a1dc9e1e812a981c66b5ffda3c6b01a8a9d113155792309fd53a3acfd054ca7776e8eec28c26480cd1e3c812f67f91d14217f39a606669d" | ||
}, | ||
|
||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jskeet updated the conformance test to include CSEK in pr: googleapis/google-cloud-dotnet#2954 |
||
"description": "Headers should be trimmed", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"headers": { | ||
"leading": [ " xyz" ], | ||
"trailing": [ "abc " ], | ||
"collapsed": [ "abc def" ] | ||
}, | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=collapsed%3Bhost%3Bleading%3Btrailing&X-Goog-Signature=1839511d6238d9ac2bbcbba8b23515b3757db35dfa7b8f9bc4b8b4aa270224df747c812526f1a3bcf294d67ed84cd14e074c36bc090e0a542782934a7c925af4a5ea68123e97533704ce8b08ccdf5fe6b412f89c9fc4de243e29abdb098382c5672188ee3f6fef7131413e252c78e7a35658825ad842a50609e9cc463731e17284ff7a14824c989f87cef22fb99dfec20cfeed69d8b3a08f00b43b8284eecd535e50e982b05cd74c5750cd5f986cfc21a2a05f7f3ab7fc31bd684ed1b823b64d29281e923fc6580c49005552ca19c253de087d9d2df881144e44eda40965cfdb4889bf3a35553c9809f4ed20b8355be481b92b9618952b6a04f3017b36053e15" | ||
}, | ||
|
||
// Headers associated with customer-supplied encryption keys should not be included in the signature | ||
{ | ||
"description": "Customer-supplied encryption key", | ||
"bucket": "test-bucket", | ||
"object": "test-object", | ||
"headers": | ||
{ | ||
"X-Goog-Encryption-Key": [ "ignored" ], | ||
"X-Goog-Encryption-Key-Sha256": [ "ignored" ], | ||
"X-Goog-Encryption-Algorithm": [ "ignored" ] | ||
}, | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74" | ||
}, | ||
|
||
{ | ||
"description": "List Objects", | ||
"bucket": "test-bucket", | ||
"object": "", | ||
"method": "GET", | ||
"expiration": 10, | ||
"timestamp": "20190201T090000Z", | ||
"expectedUrl": "https://storage.googleapis.com/test-bucket/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=2a1d342f11ddf0c90c669b9ba89ab5099f94049a86351cacbc85845fd5a8b31e1f9c8d484926c19fbd6930da6c8d3049ca8ebcfeefb7b02e53137755d36f97baab479414528b2802f10d94541facb888edf886d91ba124e60cb3801464f61aadc575fc921c99cf8c52e281f7bc0d3e740f529201c469c8e52775b6433687e0c0dca1c6b874614c3c3d09599be1e192c40ad6827416e387bf6e88a5f501f1d8225bce498d134599d0dfe30c9c833c244d3f90cf9595b9f8175658b788ee5c4a90b575fde5e83c645772250c7098373ca754b39d0fc1ebca2f50261a015931541c9827920eba67a1c41613853a1bd23299a1f9f5d583c0feb05ea2f792ba390d27" | ||
} | ||
|
||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment
x-goog-encryption-key
andx-goog-encryption-key-sha256
should be removed for both v2 and v4. There's an open question the GCS team if this is the case moving forward. (no-op for now).How does knowing v4 help here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"x-goog-encryption-key" and "x-goog-encryption-key-sha256" are removed for both v2 and v4 here. "x-goog-encyrption-algorithm" is only removed for v4 here (C# does this as well) which is why there's a check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linking you to an internal bug: 128647687. This should be clarified when we get a response there.