mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Bug 1421501 - WebIDL and DOM for PrioEncoder r=edgar,hsivonen
MozReview-Commit-ID: L8htRm3J1mZ --HG-- extra : rebase_source : ca9ccac75cd575be12d18c71ae60dbffb7c529fa
This commit is contained in:
parent
d0af2bd6c6
commit
b8233d3ae3
@ -1744,3 +1744,8 @@ pref("shield.savant.loglevel", "warn");
|
||||
|
||||
// Multi-lingual preferences
|
||||
pref("intl.multilingual.enabled", false);
|
||||
|
||||
// Prio preferences
|
||||
// Curve25519 public keys for Prio servers
|
||||
pref("prio.publicKeyA", "35AC1C7576C7C6EDD7FED6BCFC337B34D48CB4EE45C86BEEFB40BD8875707733");
|
||||
pref("prio.publicKeyB", "26E6674E65425B823F1F1D5F96E3BB3EF9E406EC7FBA7DEF8B08A35DD135AF50");
|
||||
|
@ -95,6 +95,7 @@ LOCAL_INCLUDES += [
|
||||
'/media/webrtc/signaling/src/common/time_profiling',
|
||||
'/media/webrtc/signaling/src/peerconnection',
|
||||
'/media/webrtc/trunk/',
|
||||
'/third_party/msgpack/include',
|
||||
]
|
||||
|
||||
DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
|
||||
|
22
dom/chrome-webidl/PrioEncoder.webidl
Normal file
22
dom/chrome-webidl/PrioEncoder.webidl
Normal file
@ -0,0 +1,22 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
namespace PrioEncoder {
|
||||
[Throws, NewObject]
|
||||
Promise<PrioEncodedData> encode(ByteString batchID, PrioParams params);
|
||||
};
|
||||
|
||||
dictionary PrioParams {
|
||||
required boolean startupCrashDetected;
|
||||
required boolean safeModeUsage;
|
||||
required boolean browserIsUserDefault;
|
||||
};
|
||||
|
||||
dictionary PrioEncodedData {
|
||||
Uint8Array a;
|
||||
Uint8Array b;
|
||||
};
|
@ -43,6 +43,7 @@ WEBIDL_FILES = [
|
||||
'MozStorageStatementParams.webidl',
|
||||
'MozStorageStatementRow.webidl',
|
||||
'PrecompiledScript.webidl',
|
||||
'PrioEncoder.webidl',
|
||||
'PromiseDebugging.webidl',
|
||||
'StructuredCloneHolder.webidl',
|
||||
'WebExtensionContentScript.webidl',
|
||||
|
@ -63,6 +63,7 @@ DIRS += [
|
||||
'notification',
|
||||
'offline',
|
||||
'power',
|
||||
'prio',
|
||||
'push',
|
||||
'quota',
|
||||
'security',
|
||||
|
180
dom/prio/PrioEncoder.cpp
Normal file
180
dom/prio/PrioEncoder.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
|
||||
#include "PrioEncoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ StaticRefPtr<PrioEncoder> PrioEncoder::sSingleton;
|
||||
|
||||
/* static */ PublicKey PrioEncoder::sPublicKeyA = nullptr;
|
||||
/* static */ PublicKey PrioEncoder::sPublicKeyB = nullptr;
|
||||
|
||||
PrioEncoder::PrioEncoder() = default;
|
||||
PrioEncoder::~PrioEncoder()
|
||||
{
|
||||
if (sPublicKeyA) {
|
||||
PublicKey_clear(sPublicKeyA);
|
||||
sPublicKeyA = nullptr;
|
||||
}
|
||||
|
||||
if (sPublicKeyB) {
|
||||
PublicKey_clear(sPublicKeyB);
|
||||
sPublicKeyB = nullptr;
|
||||
}
|
||||
|
||||
Prio_clear();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<Promise>
|
||||
PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SECStatus prio_rv = SECSuccess;
|
||||
|
||||
if (!sSingleton) {
|
||||
sSingleton = new PrioEncoder();
|
||||
|
||||
ClearOnShutdown(&sSingleton);
|
||||
|
||||
Prio_init();
|
||||
|
||||
nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA;
|
||||
nsresult rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB;
|
||||
rv = Preferences::GetCString("prio.publicKeyB", prioKeyB);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check that both public keys are of the right length
|
||||
// and contain only hex digits 0-9a-fA-f
|
||||
if (!PrioEncoder::IsValidHexPublicKey(prioKeyA)
|
||||
|| !PrioEncoder::IsValidHexPublicKey(prioKeyB)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyA, reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()), CURVE25519_KEY_LEN_HEX);
|
||||
if (prio_rv != SECSuccess) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyB, reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()), CURVE25519_KEY_LEN_HEX);
|
||||
if (prio_rv != SECSuccess) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
|
||||
bool dataItems[] = {
|
||||
aPrioParams.mStartupCrashDetected,
|
||||
aPrioParams.mSafeModeUsage,
|
||||
aPrioParams.mBrowserIsUserDefault
|
||||
};
|
||||
|
||||
PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems), sPublicKeyA, sPublicKeyB, reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()), aBatchID.Length());
|
||||
|
||||
if (!prioConfig) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
auto configGuard = MakeScopeExit([&] {
|
||||
PrioConfig_clear(prioConfig);
|
||||
});
|
||||
|
||||
unsigned char* forServerA = nullptr;
|
||||
unsigned int lenA = 0;
|
||||
unsigned char* forServerB = nullptr;
|
||||
unsigned int lenB = 0;
|
||||
|
||||
prio_rv = PrioClient_encode(prioConfig, dataItems, &forServerA, &lenA, &forServerB, &lenB);
|
||||
|
||||
// Package the data into the dictionary
|
||||
PrioEncodedData data;
|
||||
|
||||
nsTArray<uint8_t> arrayForServerA;
|
||||
nsTArray<uint8_t> arrayForServerB;
|
||||
|
||||
if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA), lenA, fallible)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
free(forServerA);
|
||||
|
||||
if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB), lenB, fallible)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
free(forServerB);
|
||||
|
||||
JS::Rooted<JS::Value> valueA(aGlobal.Context());
|
||||
if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
}
|
||||
data.mA.Construct().Init(&valueA.toObject());
|
||||
|
||||
JS::Rooted<JS::Value> valueB(aGlobal.Context());
|
||||
if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
}
|
||||
data.mB.Construct().Init(&valueB.toObject());
|
||||
|
||||
if (prio_rv != SECSuccess) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
promise->MaybeResolve(data);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
PrioEncoder::IsValidHexPublicKey(mozilla::Span<const char> aStr)
|
||||
{
|
||||
if (aStr.Length() != CURVE25519_KEY_LEN_HEX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto c : aStr) {
|
||||
if (!IsAsciiHexDigit(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
47
dom/prio/PrioEncoder.h
Normal file
47
dom/prio/PrioEncoder.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PrioEncoder_h
|
||||
#define mozilla_dom_PrioEncoder_h
|
||||
|
||||
#include "mozilla/dom/PrioEncoderBinding.h"
|
||||
|
||||
#include "mprio.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PrioEncoder
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PrioEncoder)
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
PrioEncoder();
|
||||
~PrioEncoder();
|
||||
|
||||
static PublicKey
|
||||
sPublicKeyA;
|
||||
|
||||
static PublicKey
|
||||
sPublicKeyB;
|
||||
|
||||
static StaticRefPtr<PrioEncoder>
|
||||
sSingleton;
|
||||
|
||||
static bool
|
||||
IsValidHexPublicKey(mozilla::Span<const char>);
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_PrioEncoder_h
|
22
dom/prio/moz.build
Normal file
22
dom/prio/moz.build
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/third_party/msgpack/include'
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'PrioEncoder.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'PrioEncoder.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
@ -120,6 +120,22 @@ IsAsciiDigit(Char aChar)
|
||||
return '0' <= uc && uc <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff |aChar| matches [0-9a-fA-F].
|
||||
*
|
||||
* This function is basically isxdigit, but guaranteed to be only for ASCII.
|
||||
*/
|
||||
template<typename Char>
|
||||
constexpr bool
|
||||
IsAsciiHexDigit(Char aChar)
|
||||
{
|
||||
using UnsignedChar = typename detail::MakeUnsignedChar<Char>::Type;
|
||||
auto uc = static_cast<UnsignedChar>(aChar);
|
||||
return ('0' <= uc && uc <= '9') ||
|
||||
('a' <= uc && uc <= 'f') ||
|
||||
('A' <= uc && uc <= 'F');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff |aChar| matches [a-zA-Z0-9].
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user