mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1205137 - Add a PushSubscription
serializer. r=mt,smaug
--HG-- extra : commitid : F5xjqIFcach extra : rebase_source : 61b0a0cbae318f7afc51752fc31a7133b8abd15c
This commit is contained in:
parent
1eabadf7aa
commit
1c0dc1a969
@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/PushManager.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/unused.h"
|
||||
@ -65,6 +66,26 @@ GetPermissionState(nsIPrincipal* aPrincipal,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionToJSON(PushSubscriptionJSON& aJSON, const nsString& aEndpoint,
|
||||
const nsTArray<uint8_t>& aRawP256dhKey,
|
||||
const nsTArray<uint8_t>& aAuthSecret)
|
||||
{
|
||||
aJSON.mEndpoint.Construct();
|
||||
aJSON.mEndpoint.Value() = aEndpoint;
|
||||
|
||||
aJSON.mKeys.mP256dh.Construct();
|
||||
nsresult rv = Base64URLEncode(aRawP256dhKey.Length(),
|
||||
aRawP256dhKey.Elements(),
|
||||
aJSON.mKeys.mP256dh.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
aJSON.mKeys.mAuth.Construct();
|
||||
rv = Base64URLEncode(aAuthSecret.Length(), aAuthSecret.Elements(),
|
||||
aJSON.mKeys.mAuth.Value());
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
|
||||
@ -123,6 +144,12 @@ PushSubscription::Unsubscribe(ErrorResult& aRv)
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
PushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
|
||||
const nsAString& aEndpoint,
|
||||
const nsAString& aScope,
|
||||
@ -507,6 +534,12 @@ WorkerPushSubscription::Unsubscribe(ErrorResult &aRv)
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
|
||||
{
|
||||
SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription)
|
||||
|
@ -104,6 +104,9 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~PushSubscription();
|
||||
|
||||
@ -197,6 +200,9 @@ public:
|
||||
already_AddRefed<Promise>
|
||||
Unsubscribe(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToJSON(PushSubscriptionJSON& aJSON);
|
||||
|
||||
protected:
|
||||
~WorkerPushSubscription();
|
||||
|
||||
|
@ -77,6 +77,47 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
});
|
||||
}
|
||||
|
||||
function base64UrlDecode(s) {
|
||||
s = s.replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
// Replace padding if it was stripped by the sender.
|
||||
// See http://tools.ietf.org/html/rfc4648#section-4
|
||||
switch (s.length % 4) {
|
||||
case 0:
|
||||
break; // No pad chars in this case
|
||||
case 2:
|
||||
s += '==';
|
||||
break; // Two pad chars
|
||||
case 3:
|
||||
s += '=';
|
||||
break; // One pad char
|
||||
default:
|
||||
throw new Error('Illegal base64url string!');
|
||||
}
|
||||
|
||||
// With correct padding restored, apply the standard base64 decoder
|
||||
var decoded = atob(s);
|
||||
|
||||
var array = new Uint8Array(new ArrayBuffer(decoded.length));
|
||||
for (var i = 0; i < decoded.length; i++) {
|
||||
array[i] = decoded.charCodeAt(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
add_task(function* compareJSONSubscription() {
|
||||
var json = pushSubscription.toJSON();
|
||||
is(json.endpoint, pushSubscription.endpoint, "Wrong endpoint");
|
||||
|
||||
["p256dh", "auth"].forEach(keyName => {
|
||||
isDeeply(
|
||||
base64UrlDecode(json.keys[keyName]),
|
||||
new Uint8Array(pushSubscription.getKey(keyName)),
|
||||
"Mismatched Base64-encoded key: " + keyName
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* comparePublicKey() {
|
||||
var data = yield sendRequestToWorker({ type: "publicKey" });
|
||||
var p256dhKey = new Uint8Array(pushSubscription.getKey("p256dh"));
|
||||
|
@ -15,6 +15,18 @@ enum PushEncryptionKeyName
|
||||
"auth"
|
||||
};
|
||||
|
||||
dictionary PushSubscriptionKeys
|
||||
{
|
||||
ByteString p256dh;
|
||||
ByteString auth;
|
||||
};
|
||||
|
||||
dictionary PushSubscriptionJSON
|
||||
{
|
||||
USVString endpoint;
|
||||
PushSubscriptionKeys keys;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
|
||||
ChromeConstructor(DOMString pushEndpoint, DOMString scope,
|
||||
ArrayBuffer? key, ArrayBuffer? authSecret)]
|
||||
@ -24,7 +36,9 @@ interface PushSubscription
|
||||
ArrayBuffer? getKey(PushEncryptionKeyName name);
|
||||
[Throws, UseCounter]
|
||||
Promise<boolean> unsubscribe();
|
||||
jsonifier;
|
||||
|
||||
// Implements the custom serializer specified in Push API, section 9.
|
||||
PushSubscriptionJSON toJSON();
|
||||
|
||||
// Used to set the principal from the JS implemented PushManager.
|
||||
[Exposed=Window,ChromeOnly]
|
||||
|
@ -225,6 +225,9 @@ EncodeInputStream(nsIInputStream* aInputStream,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char kBase64URLAlphabet[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
@ -355,4 +358,49 @@ Base64Decode(const nsAString& aBinaryData, nsAString& aString)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Base64URLEncode(uint32_t aLength, const uint8_t* aData, nsACString& aString)
|
||||
{
|
||||
// Don't encode empty strings.
|
||||
if (aLength == 0) {
|
||||
aString.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check for overflow.
|
||||
if ((static_cast<uint64_t>(aLength) * 6 + 7) / 8 > UINT32_MAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!aString.SetLength((aLength * 8 + 5) / 6, fallible)) {
|
||||
aString.Truncate();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char* rawBuffer = aString.BeginWriting();
|
||||
|
||||
uint32_t index = 0;
|
||||
for (; index + 3 <= aLength; index += 3) {
|
||||
*rawBuffer++ = kBase64URLAlphabet[aData[index] >> 2];
|
||||
*rawBuffer++ = kBase64URLAlphabet[((aData[index] & 0x3) << 4) |
|
||||
(aData[index + 1] >> 4)];
|
||||
*rawBuffer++ = kBase64URLAlphabet[((aData[index + 1] & 0xf) << 2) |
|
||||
(aData[index + 2] >> 6)];
|
||||
*rawBuffer++ = kBase64URLAlphabet[aData[index + 2] & 0x3f];
|
||||
}
|
||||
|
||||
uint32_t remaining = aLength - index;
|
||||
if (remaining == 1) {
|
||||
*rawBuffer++ = kBase64URLAlphabet[aData[index] >> 2];
|
||||
*rawBuffer++ = kBase64URLAlphabet[((aData[index] & 0x3) << 4)];
|
||||
} else if (remaining == 2) {
|
||||
*rawBuffer++ = kBase64URLAlphabet[aData[index] >> 2];
|
||||
*rawBuffer++ = kBase64URLAlphabet[((aData[index] & 0x3) << 4) |
|
||||
(aData[index + 1] >> 4)];
|
||||
*rawBuffer++ = kBase64URLAlphabet[((aData[index + 1] & 0xf) << 2)];
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -34,6 +34,14 @@ Base64Decode(const nsACString& aBinaryData, nsACString& aString);
|
||||
nsresult
|
||||
Base64Decode(const nsAString& aBinaryData, nsAString& aString);
|
||||
|
||||
/**
|
||||
* Converts |aData| to an unpadded, Base64 URL-encoded string per RFC 4648.
|
||||
* Aims to encode the data in constant time. The caller may free |aData| once
|
||||
* this function returns.
|
||||
*/
|
||||
nsresult
|
||||
Base64URLEncode(uint32_t aLength, const uint8_t* aData, nsACString& aString);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user