Commit 90128cb5 authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

Adopt ArrayBuffer to pass sync encryption keys

Encryption keys can contain non-utf8 binary content and are better
represented by ArrayBuffer being adopted in the API.

The patch also reorders the parameter order for future expansion
options.

Bug: 1000146
Change-Id: I7d1da9320c7e5c512f657deb5b211d3cf46d06d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1919935
Commit-Queue: David Trainor <dtrainor@chromium.org>
Auto-Submit: Mikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718313}
parent 3348fd5c
...@@ -40,6 +40,22 @@ bool ShouldExposeMojoApi(content::NavigationHandle* navigation_handle) { ...@@ -40,6 +40,22 @@ bool ShouldExposeMojoApi(content::NavigationHandle* navigation_handle) {
return url::Origin::Create(navigation_handle->GetURL()) == GetAllowedOrigin(); return url::Origin::Create(navigation_handle->GetURL()) == GetAllowedOrigin();
} }
// TODO(crbug.com/1027676): Migrate away from std::string and adopt some safer
// type (std::vector<uint8_t> or newly-introduced class) to represent encryption
// keys.
std::string BytesAsString(const std::vector<uint8_t>& bytes) {
return std::string(reinterpret_cast<const char*>(bytes.data()), bytes.size());
}
std::vector<std::string> EncryptionKeysAsStrings(
const std::vector<std::vector<uint8_t>>& encryption_keys) {
std::vector<std::string> encryption_keys_as_strings;
for (const auto& encryption_key : encryption_keys) {
encryption_keys_as_strings.push_back(BytesAsString(encryption_key));
}
return encryption_keys_as_strings;
}
} // namespace } // namespace
class SyncEncryptionKeysTabHelper::EncryptionKeyApi class SyncEncryptionKeysTabHelper::EncryptionKeyApi
...@@ -53,14 +69,15 @@ class SyncEncryptionKeysTabHelper::EncryptionKeyApi ...@@ -53,14 +69,15 @@ class SyncEncryptionKeysTabHelper::EncryptionKeyApi
} }
// chrome::mojom::SyncEncryptionKeysExtension: // chrome::mojom::SyncEncryptionKeysExtension:
void SetEncryptionKeys(const std::vector<std::string>& encryption_keys, void SetEncryptionKeys(
const std::string& gaia_id, const std::vector<std::vector<uint8_t>>& encryption_keys,
SetEncryptionKeysCallback callback) override { const std::string& gaia_id,
SetEncryptionKeysCallback callback) override {
CHECK_EQ(bindings_.GetCurrentTargetFrame()->GetLastCommittedOrigin(), CHECK_EQ(bindings_.GetCurrentTargetFrame()->GetLastCommittedOrigin(),
GetAllowedOrigin()); GetAllowedOrigin());
sync_service_->GetUserSettings()->AddTrustedVaultDecryptionKeys( sync_service_->GetUserSettings()->AddTrustedVaultDecryptionKeys(
gaia_id, encryption_keys); gaia_id, EncryptionKeysAsStrings(encryption_keys));
std::move(callback).Run(); std::move(callback).Run();
} }
......
...@@ -11,5 +11,5 @@ interface SyncEncryptionKeysExtension { ...@@ -11,5 +11,5 @@ interface SyncEncryptionKeysExtension {
// Provides sync encryption keys to the browser process. Returns true if no // Provides sync encryption keys to the browser process. Returns true if no
// further encryption keys are needed (which includes the case, among others, // further encryption keys are needed (which includes the case, among others,
// of encryption keys not being needed even prior to this call). // of encryption keys not being needed even prior to this call).
SetEncryptionKeys(array<string> encryption_keys, string gaia_id) => (); SetEncryptionKeys(array<array<uint8>> encryption_keys, string gaia_id) => ();
}; };
...@@ -30,6 +30,26 @@ const url::Origin& GetAllowedOrigin() { ...@@ -30,6 +30,26 @@ const url::Origin& GetAllowedOrigin() {
return *origin; return *origin;
} }
// This function is intended to convert a binary blob representing an encryption
// key and provided by the web via a Javascript ArrayBuffer.
std::vector<uint8_t> ArrayBufferAsBytes(
const v8::Local<v8::ArrayBuffer>& array_buffer) {
auto backing_store = array_buffer->GetBackingStore();
const uint8_t* start =
reinterpret_cast<const uint8_t*>(backing_store->Data());
const size_t length = backing_store->ByteLength();
return std::vector<uint8_t>(start, start + length);
}
std::vector<std::vector<uint8_t>> EncryptionKeysAsBytes(
const std::vector<v8::Local<v8::ArrayBuffer>>& encryption_keys) {
std::vector<std::vector<uint8_t>> encryption_keys_as_bytes;
for (const v8::Local<v8::ArrayBuffer>& encryption_key : encryption_keys) {
encryption_keys_as_bytes.push_back(ArrayBufferAsBytes(encryption_key));
}
return encryption_keys_as_bytes;
}
} // namespace } // namespace
// static // static
...@@ -93,31 +113,40 @@ void SyncEncryptionKeysExtension::Install() { ...@@ -93,31 +113,40 @@ void SyncEncryptionKeysExtension::Install() {
void SyncEncryptionKeysExtension::SetSyncEncryptionKeys(gin::Arguments* args) { void SyncEncryptionKeysExtension::SetSyncEncryptionKeys(gin::Arguments* args) {
DCHECK(render_frame()); DCHECK(render_frame());
// This function as exposed to the web has the following signature:
// setSyncEncryptionKeys(callback, gaia_id, encryption_keys)
//
// Where:
// callback: Allows caller to get notified upon completion.
// gaia_id: String representing the user's server-provided ID.
// encryption_keys: Array where each element is an ArrayBuffer representing
// an encryption key (binary blob).
v8::HandleScope handle_scope(args->isolate()); v8::HandleScope handle_scope(args->isolate());
std::vector<std::string> encryption_keys; v8::Local<v8::Function> callback;
if (!args->GetNext(&encryption_keys)) { if (!args->GetNext(&callback)) {
DLOG(ERROR) << "Not array of strings"; DLOG(ERROR) << "No callback";
args->ThrowError(); args->ThrowError();
return; return;
} }
if (encryption_keys.empty()) { std::string gaia_id;
DLOG(ERROR) << "Array of strings empty"; if (!args->GetNext(&gaia_id)) {
DLOG(ERROR) << "No account ID";
args->ThrowError(); args->ThrowError();
return; return;
} }
std::string gaia_id; std::vector<v8::Local<v8::ArrayBuffer>> encryption_keys;
if (!args->GetNext(&gaia_id)) { if (!args->GetNext(&encryption_keys)) {
DLOG(ERROR) << "No account ID"; DLOG(ERROR) << "Not array of strings";
args->ThrowError(); args->ThrowError();
return; return;
} }
v8::Local<v8::Function> callback; if (encryption_keys.empty()) {
if (!args->GetNext(&callback)) { DLOG(ERROR) << "Array of strings empty";
DLOG(ERROR) << "No callback";
args->ThrowError(); args->ThrowError();
return; return;
} }
...@@ -130,7 +159,7 @@ void SyncEncryptionKeysExtension::SetSyncEncryptionKeys(gin::Arguments* args) { ...@@ -130,7 +159,7 @@ void SyncEncryptionKeysExtension::SetSyncEncryptionKeys(gin::Arguments* args) {
} }
remote_->SetEncryptionKeys( remote_->SetEncryptionKeys(
encryption_keys, gaia_id, EncryptionKeysAsBytes(encryption_keys), gaia_id,
base::BindOnce(&SyncEncryptionKeysExtension::RunCompletionCallback, base::BindOnce(&SyncEncryptionKeysExtension::RunCompletionCallback,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
std::move(global_callback))); std::move(global_callback)));
......
<html> <html>
<head> <head>
<script> <script>
// This particular test page uses ASCII keys for simplicity. Real callers are
// not expected to deal with strings and converting them via charCodeAt().
// TODO(crbug.com/978430): Pass an actual binary (non-ASCII) key.
function asciiToArrayBuffer(s) {
var buffer = new ArrayBuffer(s.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < s.length; i++) {
view[i] = s.charCodeAt(i);
}
return buffer;
}
window.onload = function() { window.onload = function() {
if (typeof chrome.setSyncEncryptionKeys == "undefined") { if (typeof chrome.setSyncEncryptionKeys == "undefined") {
document.title = "UNDEFINED"; document.title = "UNDEFINED";
} else { } else {
chrome.setSyncEncryptionKeys([location.hash.substring(1)], chrome.setSyncEncryptionKeys(() => { document.title = "OK"; },
location.search.substring(1), location.search.substring(1),
() => { document.title = "OK"; }); [asciiToArrayBuffer(location.hash.substring(1))]);
} }
} }
</script> </script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment