import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1172382 - Enable AccessibleCaret on B2G. r=roc (f5c58c2798)
- remove duplicated (8823cc4a43)
- Bug 1219310 - part 1 - ask the prefs file for its size directly; r=njn (93073cbc5e)
- Bug 1219310 - part 2 - keep track of how much pref file we have read; r=njn (6a2a10a8b1)
- Bug 1213123 - Make Preferences::SetString accept char16ptr_t instead of char16_t*. r=froydnj (a895a36861)
- Bug 1216901 - Make the FasterMake backend reticulate splines when moz.build or jar.mn files are modified. r=mshal (ed4ec93b18)
- Bug 1219122 - Move webapprt.ini definition to moz.build. - Add corresponding webpprt files. (da6bc91b5c)
- Bug 1219126 - Move greprefs.js definition in moz.build. r=mshal (52f404c935)
- code style (1b1e543834)
- Bug 1162690 - Remove malformed uri warning in nsURLParser::ParseURL r=mcmanus (8534fcebb7)
- Bug 1163028 - URL: stop escaping [ and ] in path r=mcmanus (f2f3deec40)
- Bug 1163030 - URL: stop escaping ` in query r=mcmanus (17d6c07640)
- Bug 1191423 - Disallow illegal characters in cookies set via HTTP. r=jduell (b1786d140f)
- Bug 1210235 - Skip package verification if pref out or no signature. The package would be treated unsigned. r=valentin (63870dd7ef)
- Bug 1216062 - Notify OnStartSignedPackagedRequest with package identifier. r=valentin. (81a14af3db)
- Bug 1214079 - Doom the package cache if the signature verification failed. r=valentin (83824c2d5d)
- Bug 1178448 - Use imported CA in developer mode. r=keeler,valentin (b9cf64b477)
- Bug 1216469 - Bypass verification for signed packages from trust origins. r=valentin (a36d0a6d2f)
- Bug 1218284 - Match signed packages' with trust origin without suffix. r=valentin (45529dc7df)
- Bug 412457 - should unescape hostname first, then perform IDNA r=mcmanus (23ebe47574)
- Bug 1217316 - Remove for-each from netwerk/. r=jduell (8d0ca69e9e)
- Bug 1208847 - Add telemetry to measure how often secure cookies are set from non-secure origins r=mcmanus (57ecf3651d)
- Bug 1165267 - Part 1: Replace appId and inBrowser by originAttributes v2. r=honzab (7710301407)
- Bug 1165267 - Fix downgrading issue by restoring appId and inBrowserElement columns v3. r=honzab (3e8b8e4dfb)
- Bug 1221049 - Use originAttributes from TabContext. r=kanru (5eaebe3b28)
- Bug 1197944 - Change pref so that the http auth dialog is presented for sub resources as well. r=jduell (e3a7e2a1a7)
- Bug 1202421 - Rename the network.auth.allow-subresource-auth pref. r=michal (87e29e1fdf)
- Bug 1213577 - Use OriginAttributes in nsHttpAuthManager, r=mcmanus (33d0a25ac4)
- Bug 961049 - Part 1: Remove unused members and methods; r=baku (0f3e6de06b)
This commit is contained in:
2023-03-10 15:32:42 +08:00
parent 40ee015dc8
commit 33f0551ea5
84 changed files with 2551 additions and 591 deletions
+3
View File
@@ -1056,6 +1056,9 @@ pref("dom.wakelock.enabled", true);
// Enable webapps add-ons
pref("dom.apps.customization.enabled", true);
// New implementation to unify touch-caret and selection-carets.
pref("layout.accessiblecaret.enabled", true);
// Enable touch caret by default
pref("touchcaret.enabled", true);
+12 -4
View File
@@ -24,6 +24,8 @@
# python/mozbuild/mozbuild/backend/fastermake.py is the following:
# - TOPSRCDIR/TOPOBJDIR, respectively the top source directory and the top
# object directory
# - BACKEND, the path to the file the backend will always update when running
# mach build-backend
# - PYTHON, the path to the python executable
# - ACDEFINES, which contains a set of -Dvar=name to be used during
# preprocessing
@@ -41,9 +43,7 @@ default: $(addprefix install-,$(INSTALL_MANIFESTS))
# Explicit files to be built for a default build
default: $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS))
default: $(TOPOBJDIR)/dist/bin/greprefs.js
default: $(TOPOBJDIR)/dist/bin/platform.ini
default: $(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini
# Targets from the recursive make backend to be built for a default build
default: $(TOPOBJDIR)/config/makefiles/xpidl/xpidl
@@ -69,12 +69,22 @@ $(TOPOBJDIR)/%: FORCE
# fallback
$(TOPOBJDIR)/faster/%: ;
# Files under the python virtualenv, which are dependencies of the BACKEND
# file, are not meant to use the fallback either.
$(TOPOBJDIR)/_virtualenv/%: ;
# And files under dist/ are meant to be copied from their first dependency
# if there is no other rule.
$(TOPOBJDIR)/dist/%:
rm -f $@
cp $< $@
# Refresh backend
$(BACKEND):
cd $(TOPOBJDIR) && $(PYTHON) config.status --backend FasterMake
$(MAKEFILE_LIST): $(BACKEND)
# Install files using install manifests
#
# The list of base directories is given in INSTALL_MANIFESTS. The
@@ -115,9 +125,7 @@ $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)): FORCE
# that are not supported by data in moz.build.
# Files to build with the recursive backend and simply copy
$(TOPOBJDIR)/dist/bin/greprefs.js: $(TOPOBJDIR)/modules/libpref/greprefs.js
$(TOPOBJDIR)/dist/bin/platform.ini: $(TOPOBJDIR)/toolkit/xre/platform.ini
$(TOPOBJDIR)/dist/bin/webapprt/webapprt.ini: $(TOPOBJDIR)/webapprt/webapprt.ini
# The xpidl target in config/makefiles/xpidl requires the install manifest for
# dist/idl to have been processed.
+1 -1
View File
@@ -77,7 +77,7 @@ public:
bool aIsContent,
bool aUsePrivateBrowsing,
bool aUseRemoteTabs,
OriginAttributes& aAttrs)
const OriginAttributes& aAttrs)
: mTopFrameElement(do_GetWeakReference(aTopFrameElement))
, mNestedFrameId(0)
, mIsContent(aIsContent)
+1 -16
View File
@@ -1101,7 +1101,6 @@ PermissionRequestChildProcessActor::Recv__delete__(
BackgroundRequestChildBase::BackgroundRequestChildBase(IDBRequest* aRequest)
: mRequest(aRequest)
, mActorDestroyed(false)
{
MOZ_ASSERT(aRequest);
aRequest->AssertIsOnOwningThread();
@@ -1127,15 +1126,6 @@ BackgroundRequestChildBase::AssertIsOnOwningThread() const
#endif // DEBUG
void
BackgroundRequestChildBase::NoteActorDestroyed()
{
AssertIsOnOwningThread();
MOZ_ASSERT(!mActorDestroyed);
mActorDestroyed = true;
}
/*******************************************************************************
* BackgroundFactoryChild
******************************************************************************/
@@ -1280,8 +1270,7 @@ BackgroundFactoryRequestChild::GetOpenDBRequest() const
{
AssertIsOnOwningThread();
IDBRequest* baseRequest = BackgroundRequestChildBase::GetDOMObject();
return static_cast<IDBOpenDBRequest*>(baseRequest);
return static_cast<IDBOpenDBRequest*>(mRequest.get());
}
bool
@@ -1362,8 +1351,6 @@ BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy)
MaybeCollectGarbageOnIPCMessage();
NoteActorDestroyed();
if (aWhy != Deletion) {
IDBOpenDBRequest* openRequest = GetOpenDBRequest();
if (openRequest) {
@@ -2447,8 +2434,6 @@ BackgroundRequestChild::ActorDestroy(ActorDestroyReason aWhy)
MaybeCollectGarbageOnIPCMessage();
NoteActorDestroyed();
if (mTransaction) {
mTransaction->AssertIsOnOwningThread();
-20
View File
@@ -218,9 +218,6 @@ class BackgroundRequestChildBase
protected:
RefPtr<IDBRequest> mRequest;
private:
bool mActorDestroyed;
public:
void
AssertIsOnOwningThread() const
@@ -230,28 +227,11 @@ public:
{ }
#endif
IDBRequest*
GetDOMObject() const
{
AssertIsOnOwningThread();
return mRequest;
}
bool
IsActorDestroyed() const
{
AssertIsOnOwningThread();
return mActorDestroyed;
}
protected:
explicit BackgroundRequestChildBase(IDBRequest* aRequest);
virtual
~BackgroundRequestChildBase();
void
NoteActorDestroyed();
};
class BackgroundFactoryRequestChild final
-10
View File
@@ -473,16 +473,6 @@ IDBFactory::IsChrome() const
return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo;
}
void
IDBFactory::SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aBackgroundActor);
MOZ_ASSERT(!mBackgroundActor);
mBackgroundActor = aBackgroundActor;
}
void
IDBFactory::IncrementParentLoggingRequestSerialNumber()
{
-3
View File
@@ -121,9 +121,6 @@ public:
{ }
#endif
void
SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor);
void
ClearBackgroundActor()
{
+1 -2
View File
@@ -5225,8 +5225,7 @@ ContentParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
}
RefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
new mozilla::docshell::OfflineCacheUpdateParent(
tabContext.OwnOrContainingAppId(),
tabContext.IsBrowserElement());
tabContext.OriginAttributesRef());
// Use this reference as the IPDL reference.
return update.forget().take();
}
+1 -3
View File
@@ -2821,13 +2821,11 @@ TabParent::GetLoadContext()
if (mLoadContext) {
loadContext = mLoadContext;
} else {
// TODO Bug 1191740 - Add OriginAttributes in TabContext
OriginAttributes attrs = OriginAttributes(OwnOrContainingAppId(), IsBrowserElement());
loadContext = new LoadContext(GetOwnerElement(),
true /* aIsContent */,
mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW,
mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW,
attrs);
OriginAttributesRef());
mLoadContext = loadContext;
}
return loadContext.forget();
@@ -12,7 +12,7 @@
SimpleTest.waitForExplicitFinish();
// Turn off the authentication dialog blocking for this test.
SpecialPowers.setIntPref("network.auth.allow-subresource-auth", 2)
SpecialPowers.setIntPref("network.auth.subresource-http-auth-allow", 2)
var tests = [
// Not the same origin no CORS asked for, should have silence
@@ -18,9 +18,9 @@
// c) Schema 3: the 'creationTime' column already exists; or the
// 'moz_uniqueid' index already exists.
let COOKIE_DATABASE_SCHEMA_CURRENT = 5;
var COOKIE_DATABASE_SCHEMA_CURRENT = 7;
let test_generator = do_run_test();
var test_generator = do_run_test();
function run_test() {
do_test_pending();
+8 -3
View File
@@ -1001,8 +1001,8 @@ static nsresult openPrefFile(nsIFile* aFile)
if (NS_FAILED(rv))
return rv;
uint64_t fileSize64;
rv = inStr->Available(&fileSize64);
int64_t fileSize64;
rv = aFile->GetFileSize(&fileSize64);
if (NS_FAILED(rv))
return rv;
NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
@@ -1018,6 +1018,7 @@ static nsresult openPrefFile(nsIFile* aFile)
// Read is not guaranteed to return a buf the size of fileSize,
// but usually will.
nsresult rv2 = NS_OK;
uint32_t offset = 0;
for (;;) {
uint32_t amtRead = 0;
rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
@@ -1025,6 +1026,10 @@ static nsresult openPrefFile(nsIFile* aFile)
break;
if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
rv2 = NS_ERROR_FILE_CORRUPTED;
offset += amtRead;
if (offset == fileSize) {
break;
}
}
PREF_FinalizeParseState(&ps);
@@ -1515,7 +1520,7 @@ Preferences::SetCString(const char* aPref, const nsACString &aValue)
// static
nsresult
Preferences::SetString(const char* aPref, const char16_t* aValue)
Preferences::SetString(const char* aPref, const char16ptr_t aValue)
{
ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+1 -1
View File
@@ -202,7 +202,7 @@ public:
static nsresult SetFloat(const char* aPref, float aValue);
static nsresult SetCString(const char* aPref, const char* aValue);
static nsresult SetCString(const char* aPref, const nsACString &aValue);
static nsresult SetString(const char* aPref, const char16_t* aValue);
static nsresult SetString(const char* aPref, const char16ptr_t aValue);
static nsresult SetString(const char* aPref, const nsAString &aValue);
static nsresult SetComplex(const char* aPref, const nsIID &aType,
+12
View File
@@ -0,0 +1,12 @@
#include ../../netwerk/base/security-prefs.js
#include init/all.js
#ifdef MOZ_DATA_REPORTING
#include ../../services/datareporting/datareporting-prefs.js
#endif
#ifdef MOZ_SERVICES_HEALTHREPORT
#if MOZ_WIDGET_TOOLKIT == android
#include ../../mobile/android/chrome/content/healthreport-prefs.js
#else
#include ../../services/healthreport/healthreport-prefs.js
#endif
#endif
+6 -11
View File
@@ -1773,10 +1773,9 @@ pref("network.http.enforce-framing.soft", true);
// See http://www.w3.org/TR/web-packaging/#streamable-package-format
pref("network.http.enable-packaged-apps", false);
// Enable this pref to skip verification process. The packaged app
// will be considered signed no matter the package has a valid/invalid
// signature or no signature.
pref("network.http.packaged-apps-developer-mode", false);
// Enable this to bring in the signature verification if the signature exists.
// Set to false if you don't need the signed packaged web app support (i.e. NSec).
pref("network.http.signed-packages.enabled", false);
// default values for FTP
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
@@ -2120,7 +2119,7 @@ pref("network.generic-ntlm-auth.workstation", "WORKSTATION");
// 1 - allow sub-resources to open HTTP authentication credentials dialogs,
// but don't allow it for cross-origin sub-resources
// 2 - allow the cross-origin authentication as well.
pref("network.auth.allow-subresource-auth", 1);
pref("network.auth.subresource-http-auth-allow", 2);
pref("permissions.default.image", 1); // 1-Accept, 2-Deny, 3-dontAcceptForeign
@@ -4625,10 +4624,6 @@ pref("layers.offmainthreadcomposition.frame-rate", -1);
pref("layers.async-pan-zoom.enabled", true);
#endif
#ifdef MOZ_WIDGET_UIKIT
pref("layers.async-pan-zoom.enabled", true);
#endif
#ifdef XP_MACOSX
pref("layers.enable-tiles", true);
pref("layers.tile-width", 512);
@@ -5143,7 +5138,7 @@ pref("browser.trackingprotection.gethashURL", "https://tracking.services.mozilla
// Turn off Spatial navigation by default.
pref("snav.enabled", false);
// Turn off touch caret by default.
// Original caret implementation on collapsed selection.
pref("touchcaret.enabled", false);
// This will inflate the size of the touch caret frame when checking if user
@@ -5155,7 +5150,7 @@ pref("touchcaret.inflatesize.threshold", 40);
// In milliseconds. (0 means disable this feature)
pref("touchcaret.expiration.time", 3000);
// Turn off selection caret by default
// Original caret implementation on non-collapsed selection.
pref("selectioncaret.enabled", false);
// This will inflate size of selection caret frame when we checking if
+3
View File
@@ -46,3 +46,6 @@ DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
DIST_FILES += [
'greprefs.js',
]
+1 -1
View File
@@ -153,7 +153,7 @@ FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
uint32_t aMaxFrames, void* aClosure, void** aBp,
void* aStackEnd);
}
} // namespace mozilla
/**
* Initialize the critical sections for this platform so that we can
+3 -3
View File
@@ -277,7 +277,7 @@ nsFileStreamBase::Write(const char *buf, uint32_t count, uint32_t *result)
*result = cnt;
return NS_OK;
}
nsresult
nsFileStreamBase::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
{
@@ -698,7 +698,7 @@ nsPartialFileInputStream::Init(nsIFile* aFile, uint64_t aStart,
nsresult rv = nsFileInputStream::Init(aFile, aIOFlags, aPerm,
aBehaviorFlags);
NS_ENSURE_SUCCESS(rv, rv);
return nsFileInputStream::Seek(NS_SEEK_SET, mStart);
}
@@ -833,7 +833,7 @@ NS_IMPL_ISUPPORTS_INHERITED(nsFileOutputStream,
nsFileStreamBase,
nsIOutputStream,
nsIFileOutputStream)
nsresult
nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
+3 -2
View File
@@ -24,7 +24,7 @@ interface nsIVerificationCallback;
* https://wiki.mozilla.org/FirefoxOS/New_security_model/Packaging
*/
[scriptable, uuid(cc245638-6a38-4f70-8d77-21c55aabd636)]
[scriptable, uuid(edf91fee-ef4a-4479-9136-27eb3b7a6312)]
interface nsIPackagedAppUtils : nsISupports
{
/**
@@ -37,7 +37,8 @@ interface nsIPackagedAppUtils : nsISupports
*/
void verifyManifest(in ACString aHeader,
in ACString aManifest,
in nsIVerificationCallback aVerifier);
in nsIVerificationCallback aVerifier,
in boolean aDeveloperMode);
/**
* @aFileName is the name of a resource in the package
+4 -3
View File
@@ -17,11 +17,12 @@ interface nsIPackagedAppVerifierListener;
* onStartRequest/onDataAvailable/onStopRequest.
*
*/
[scriptable, uuid(16419a80-4cc3-11e5-b970-0800200c9a66)]
[scriptable, uuid(37a5c208-0fce-4ad6-8431-aeb904dfe543)]
interface nsIPackagedAppVerifier : nsIStreamListener
{
// The package origin of either a signed or unsigned package.
readonly attribute ACString packageOrigin;
// The package identifier of the signed package. For a unsigned package, this
// attribute is empty.
readonly attribute ACString packageIdentifier;
// Whether this package is signed.
readonly attribute boolean isPackageSigned;
+34 -23
View File
@@ -383,7 +383,7 @@ nsStandardURL::InvalidateCache(bool invalidateCachedFile)
mSpecEncoding = eEncoding_Unknown;
}
bool
nsresult
nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
{
// If host is ACE, then convert to UTF-8. Else, if host is already UTF-8,
@@ -407,16 +407,16 @@ nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
}
}
if (gIDN &&
NS_SUCCEEDED(gIDN->ConvertToDisplayIDN(host, &isASCII, result))) {
if (!isASCII)
result.Truncate();
nsresult rv = NS_ERROR_UNEXPECTED;
if (gIDN) {
rv = gIDN->ConvertToDisplayIDN(host, &isASCII, result);
if (NS_SUCCEEDED(rv) && !isASCII) {
mHostEncoding = eEncoding_UTF8;
return true;
}
}
result.Truncate();
return false;
return rv;
}
bool
@@ -446,7 +446,9 @@ nsStandardURL::ValidIPv6orHostname(const char *host, uint32_t length)
const char *end = host + length;
if (end != net_FindCharInSet(host, end, "\t\n\v\f\r #/:?@[\\]")) {
// % is allowed because we don't do hostname percent decoding yet.
// We still allow % because it is in the ID of addons.
// Any percent encoded ASCII characters that are not allowed in the
// hostname are not percent decoded, and will be parsed just fine.
return false;
}
@@ -583,19 +585,22 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
mHostEncoding = eEncoding_ASCII;
// Note that we don't disallow URLs without a host - file:, etc
if (mHost.mLen > 0) {
const nsCSubstring& tempHost =
Substring(spec + mHost.mPos, spec + mHost.mPos + mHost.mLen);
nsAutoCString tempHost;
NS_UnescapeURL(spec + mHost.mPos, mHost.mLen, esc_AlwaysCopy | esc_Host, tempHost);
if (tempHost.Contains('\0'))
return NS_ERROR_MALFORMED_URI; // null embedded in hostname
if (tempHost.Contains(' '))
return NS_ERROR_MALFORMED_URI; // don't allow spaces in the hostname
if ((useEncHost = NormalizeIDN(tempHost, encHost)))
approxLen += encHost.Length();
else
approxLen += mHost.mLen;
nsresult rv = NormalizeIDN(tempHost, encHost);
if (NS_FAILED(rv)) {
return rv;
}
if ((useEncHost && !ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) ||
(!useEncHost && !ValidIPv6orHostname(tempHost.BeginReading(), tempHost.Length()))) {
// NormalizeIDN always copies, if the call was successful.
useEncHost = true;
approxLen += encHost.Length();
if (!ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) {
return NS_ERROR_MALFORMED_URI;
}
}
@@ -1663,7 +1668,11 @@ nsStandardURL::SetHost(const nsACString &input)
FindHostLimit(start, end);
const nsCString flat(Substring(start, end));
const nsCString unescapedHost(Substring(start, end));
// Do percent decoding on the the input.
nsAutoCString flat;
NS_UnescapeURL(unescapedHost.BeginReading(), unescapedHost.Length(),
esc_AlwaysCopy | esc_Host, flat);
const char *host = flat.get();
LOG(("nsStandardURL::SetHost [host=%s]\n", host));
@@ -1694,12 +1703,14 @@ nsStandardURL::SetHost(const nsACString &input)
uint32_t len;
nsAutoCString hostBuf;
if (NormalizeIDN(flat, hostBuf)) {
host = hostBuf.get();
len = hostBuf.Length();
nsresult rv = NormalizeIDN(flat, hostBuf);
if (NS_FAILED(rv)) {
return rv;
}
else
len = flat.Length();
// NormalizeIDN always copies if the call was successful
host = hostBuf.get();
len = hostBuf.Length();
if (!ValidIPv6orHostname(host, len)) {
return NS_ERROR_MALFORMED_URI;
+1 -1
View File
@@ -178,7 +178,7 @@ private:
void InvalidateCache(bool invalidateCachedFile = true);
bool ValidIPv6orHostname(const char *host, uint32_t aLen);
bool NormalizeIDN(const nsCSubstring &host, nsCString &result);
nsresult NormalizeIDN(const nsCSubstring &host, nsCString &result);
void CoalescePath(netCoalesceFlags coalesceFlag, char *path);
uint32_t AppendSegmentToBuf(char *, uint32_t, const char *,
-2
View File
@@ -119,7 +119,6 @@ nsBaseURLParser::ParseURL(const char *spec, int32_t specLen,
// spec = <scheme>:<path-no-slashes>
//
if (!net_IsValidScheme(spec, colon - spec) || (*(colon+1) == ':')) {
NS_WARNING("malformed uri");
return NS_ERROR_MALFORMED_URI;
}
SET_RESULT(scheme, offset, colon - spec);
@@ -577,7 +576,6 @@ nsAuthURLParser::ParseServerInfo(const char *serverinfo, int32_t serverinfoLen,
break;
case ' ':
// hostname must not contain a space
NS_WARNING("malformed hostname");
return NS_ERROR_MALFORMED_URI;
}
}
+20 -31
View File
@@ -27,15 +27,13 @@ namespace {
// Ignore failures from this function, as they only affect whether we do or
// don't show a dialog box in private browsing mode if the user sets a pref.
void
CreateDummyChannel(nsIURI* aHostURI, uint32_t aAppId, bool aInMozBrowser,
bool aIsPrivate, nsIChannel **aChannel)
CreateDummyChannel(nsIURI* aHostURI, OriginAttributes &aAttrs, bool aIsPrivate,
nsIChannel **aChannel)
{
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
MOZ_ASSERT(aAttrs.mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
// TODO: Bug 1165267 - Use OriginAttributes for nsCookieService
OriginAttributes attrs(aAppId, aInMozBrowser);
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateCodebasePrincipal(aHostURI, attrs);
BasePrincipal::CreateCodebasePrincipal(aHostURI, aAttrs);
if (!principal) {
return;
}
@@ -66,28 +64,22 @@ namespace net {
MOZ_WARN_UNUSED_RESULT
bool
CookieServiceParent::GetAppInfoFromParams(const IPC::SerializedLoadContext &aLoadContext,
uint32_t& aAppId,
bool& aIsInBrowserElement,
bool& aIsPrivate)
CookieServiceParent::GetOriginAttributesFromParams(const IPC::SerializedLoadContext &aLoadContext,
OriginAttributes& aAttrs,
bool& aIsPrivate)
{
aAppId = NECKO_NO_APP_ID;
aIsInBrowserElement = false;
aIsPrivate = false;
OriginAttributes attrs;
const char* error = NeckoParent::GetValidatedAppInfo(aLoadContext,
Manager()->Manager(),
attrs);
aAttrs);
if (error) {
NS_WARNING(nsPrintfCString("CookieServiceParent: GetAppInfoFromParams: "
NS_WARNING(nsPrintfCString("CookieServiceParent: GetOriginAttributesFromParams: "
"FATAL error: %s: KILLING CHILD PROCESS\n",
error).get());
return false;
}
aAppId = attrs.mAppId;
aIsInBrowserElement = attrs.mInBrowser;
if (aLoadContext.IsPrivateBitValid()) {
aIsPrivate = aLoadContext.mUsePrivateBrowsing;
}
@@ -133,16 +125,15 @@ CookieServiceParent::RecvGetCookieString(const URIParams& aHost,
if (!hostURI)
return false;
uint32_t appId;
bool isInBrowserElement, isPrivate;
bool valid = GetAppInfoFromParams(aLoadContext, appId,
isInBrowserElement, isPrivate);
OriginAttributes attrs;
bool isPrivate;
bool valid = GetOriginAttributesFromParams(aLoadContext, attrs, isPrivate);
if (!valid) {
return false;
}
mCookieService->GetCookieStringInternal(hostURI, aIsForeign, aFromHttp, appId,
isInBrowserElement, isPrivate, *aResult);
mCookieService->GetCookieStringInternal(hostURI, aIsForeign, aFromHttp, attrs,
isPrivate, *aResult);
return true;
}
@@ -164,10 +155,9 @@ CookieServiceParent::RecvSetCookieString(const URIParams& aHost,
if (!hostURI)
return false;
uint32_t appId;
bool isInBrowserElement, isPrivate;
bool valid = GetAppInfoFromParams(aLoadContext, appId,
isInBrowserElement, isPrivate);
OriginAttributes attrs;
bool isPrivate;
bool valid = GetOriginAttributesFromParams(aLoadContext, attrs, isPrivate);
if (!valid) {
return false;
}
@@ -180,14 +170,13 @@ CookieServiceParent::RecvSetCookieString(const URIParams& aHost,
// with aIsForeign before we have to worry about nsCookiePermission trying
// to use the channel to inspect it.
nsCOMPtr<nsIChannel> dummyChannel;
CreateDummyChannel(hostURI, appId, isInBrowserElement,
isPrivate, getter_AddRefs(dummyChannel));
CreateDummyChannel(hostURI, attrs, isPrivate, getter_AddRefs(dummyChannel));
// NB: dummyChannel could be null if something failed in CreateDummyChannel.
nsDependentCString cookieString(aCookieString, 0);
mCookieService->SetCookieStringInternal(hostURI, aIsForeign, cookieString,
aServerTime, aFromHttp, appId,
isInBrowserElement, isPrivate, dummyChannel);
aServerTime, aFromHttp, attrs,
isPrivate, dummyChannel);
return true;
}
+4 -4
View File
@@ -10,6 +10,7 @@
#include "SerializedLoadContext.h"
class nsCookieService;
namespace mozilla { class OriginAttributes; }
namespace mozilla {
namespace net {
@@ -22,10 +23,9 @@ public:
protected:
MOZ_WARN_UNUSED_RESULT bool
GetAppInfoFromParams(const IPC::SerializedLoadContext &aLoadContext,
uint32_t& aAppId,
bool& aIsInBrowserElement,
bool& aIsPrivate);
GetOriginAttributesFromParams(const IPC::SerializedLoadContext &aLoadContext,
OriginAttributes& aAttrs,
bool& aIsPrivate);
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+351 -105
View File
@@ -50,6 +50,7 @@
#include "mozIApplication.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIConsoleService.h"
#include "nsVariant.h"
using namespace mozilla;
using namespace mozilla::net;
@@ -59,7 +60,7 @@ using namespace mozilla::net;
// on content processes (see bug 777620), change to use the appropriate app
// namespace. For now those IDLs aren't supported on child processes.
#define DEFAULT_APP_KEY(baseDomain) \
nsCookieKey(baseDomain, NECKO_NO_APP_ID, false)
nsCookieKey(baseDomain, OriginAttributes())
/******************************************************************************
* nsCookieService impl:
@@ -73,7 +74,7 @@ static nsCookieService *gCookieService;
#define HTTP_ONLY_PREFIX "#HttpOnly_"
#define COOKIES_FILE "cookies.sqlite"
#define COOKIES_SCHEMA_VERSION 5
#define COOKIES_SCHEMA_VERSION 7
// parameter indexes; see EnsureReadDomain, EnsureReadComplete and
// ReadCookieDBListener::HandleResult
@@ -87,8 +88,7 @@ static nsCookieService *gCookieService;
#define IDX_SECURE 7
#define IDX_HTTPONLY 8
#define IDX_BASE_DOMAIN 9
#define IDX_APP_ID 10
#define IDX_BROWSER_ELEM 11
#define IDX_ORIGIN_ATTRIBUTES 10
static const int64_t kCookiePurgeAge =
int64_t(30 * 24 * 60 * 60) * PR_USEC_PER_SEC; // 30 days in microseconds
@@ -485,8 +485,11 @@ public:
CookieDomainTuple *tuple = mDBState->hostArray.AppendElement();
row->GetUTF8String(IDX_BASE_DOMAIN, tuple->key.mBaseDomain);
tuple->key.mAppId = static_cast<uint32_t>(row->AsInt32(IDX_APP_ID));
tuple->key.mInBrowserElement = static_cast<bool>(row->AsInt32(IDX_BROWSER_ELEM));
nsAutoCString suffix;
row->GetUTF8String(IDX_ORIGIN_ATTRIBUTES, suffix);
tuple->key.mOriginAttributes.PopulateFromSuffix(suffix);
tuple->cookie = gCookieService->GetCookieFromRow(row);
}
@@ -564,20 +567,21 @@ public:
// nsIObserver implementation.
NS_IMETHODIMP
Observe(nsISupports *aSubject, const char *aTopic, const char16_t *data) override
Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) override
{
MOZ_ASSERT(!nsCRT::strcmp(aTopic, TOPIC_WEB_APP_CLEAR_DATA));
MOZ_ASSERT(!nsCRT::strcmp(aTopic, TOPIC_CLEAR_ORIGIN_DATA));
uint32_t appId = NECKO_UNKNOWN_APP_ID;
bool browserOnly = false;
nsresult rv = NS_GetAppInfoFromClearDataNotification(aSubject, &appId,
&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(XRE_IsParentProcess());
OriginAttributes attrs;
MOZ_ALWAYS_TRUE(attrs.Init(nsDependentString(aData)));
nsCOMPtr<nsICookieManager2> cookieManager
= do_GetService(NS_COOKIEMANAGER_CONTRACTID);
MOZ_ASSERT(cookieManager);
return cookieManager->RemoveCookiesForApp(appId, browserOnly);
// TODO: We should add a new interface RemoveCookiesForOriginAttributes in
// nsICookieManager2 and use it instead of RemoveCookiesForApp.
return cookieManager->RemoveCookiesForApp(attrs.mAppId, attrs.mInBrowser);
}
};
@@ -677,7 +681,7 @@ nsCookieService::AppClearDataObserverInit()
{
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
nsCOMPtr<nsIObserver> obs = new AppClearDataObserver();
observerService->AddObserver(obs, TOPIC_WEB_APP_CLEAR_DATA,
observerService->AddObserver(obs, TOPIC_CLEAR_ORIGIN_DATA,
/* holdsWeak= */ false);
}
@@ -802,6 +806,108 @@ nsCookieService::InitDBStates()
}
}
namespace {
class ConvertAppIdToOriginAttrsSQLFunction final : public mozIStorageFunction
{
~ConvertAppIdToOriginAttrsSQLFunction() {}
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEFUNCTION
};
NS_IMPL_ISUPPORTS(ConvertAppIdToOriginAttrsSQLFunction, mozIStorageFunction);
NS_IMETHODIMP
ConvertAppIdToOriginAttrsSQLFunction::OnFunctionCall(
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
{
nsresult rv;
int32_t appId, inBrowser;
rv = aFunctionArguments->GetInt32(0, &appId);
NS_ENSURE_SUCCESS(rv, rv);
rv = aFunctionArguments->GetInt32(1, &inBrowser);
NS_ENSURE_SUCCESS(rv, rv);
// Create an originAttributes object by appId and inBrowserElemnt.
// Then create the originSuffix string from this object.
OriginAttributes attrs(appId, (inBrowser ? 1 : 0));
nsAutoCString suffix;
attrs.CreateSuffix(suffix);
RefPtr<nsVariant> outVar(new nsVariant());
rv = outVar->SetAsAUTF8String(suffix);
NS_ENSURE_SUCCESS(rv, rv);
outVar.forget(aResult);
return NS_OK;
}
class SetAppIdFromOriginAttributesSQLFunction final : public mozIStorageFunction
{
~SetAppIdFromOriginAttributesSQLFunction() {}
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEFUNCTION
};
NS_IMPL_ISUPPORTS(SetAppIdFromOriginAttributesSQLFunction, mozIStorageFunction);
NS_IMETHODIMP
SetAppIdFromOriginAttributesSQLFunction::OnFunctionCall(
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
{
nsresult rv;
nsAutoCString suffix;
OriginAttributes attrs;
rv = aFunctionArguments->GetUTF8String(0, suffix);
NS_ENSURE_SUCCESS(rv, rv);
attrs.PopulateFromSuffix(suffix);
RefPtr<nsVariant> outVar(new nsVariant());
rv = outVar->SetAsInt32(attrs.mAppId);
NS_ENSURE_SUCCESS(rv, rv);
outVar.forget(aResult);
return NS_OK;
}
class SetInBrowserFromOriginAttributesSQLFunction final :
public mozIStorageFunction
{
~SetInBrowserFromOriginAttributesSQLFunction() {}
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEFUNCTION
};
NS_IMPL_ISUPPORTS(SetInBrowserFromOriginAttributesSQLFunction,
mozIStorageFunction);
NS_IMETHODIMP
SetInBrowserFromOriginAttributesSQLFunction::OnFunctionCall(
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
{
nsresult rv;
nsAutoCString suffix;
OriginAttributes attrs;
rv = aFunctionArguments->GetUTF8String(0, suffix);
NS_ENSURE_SUCCESS(rv, rv);
attrs.PopulateFromSuffix(suffix);
RefPtr<nsVariant> outVar(new nsVariant());
rv = outVar->SetAsInt32(attrs.mInBrowser);
NS_ENSURE_SUCCESS(rv, rv);
outVar.forget(aResult);
return NS_OK;
}
} // namespace
/* Attempt to open and read the database. If 'aRecreateDB' is true, try to
* move the existing database file out of the way and create a new one.
*
@@ -1062,7 +1168,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Create new table (with new fields and new unique constraint)
rv = CreateTable();
rv = CreateTableForSchemaVersion5();
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Copy data from old table, using appId/inBrowser=0 for existing rows
@@ -1080,9 +1186,127 @@ nsCookieService::TryInitDB(bool aRecreateDB)
"DROP TABLE moz_cookies_old"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
COOKIE_LOGSTRING(LogLevel::Debug,
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 5"));
}
// Fall through to the next upgrade.
case 5:
{
// Change in the version: Replace the columns |appId| and
// |inBrowserElement| by a single column |originAttributes|.
//
// Why we made this change: FxOS new security model (NSec) encapsulates
// "appId/inBrowser" in nsIPrincipal::originAttributes to make it easier
// to modify the contents of this structure in the future.
//
// We do the migration in several steps:
// 1. Rename the old table.
// 2. Create a new table.
// 3. Copy data from the old table to the new table; convert appId and
// inBrowserElement to originAttributes in the meantime.
// Rename existing table.
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_cookies RENAME TO moz_cookies_old"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Drop existing index (CreateTable will create new one for new table).
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP INDEX moz_basedomain"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Create new table with new fields and new unique constraint.
rv = CreateTable();
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Copy data from old table without the two deprecated columns appId and
// inBrowserElement.
nsCOMPtr<mozIStorageFunction>
convertToOriginAttrs(new ConvertAppIdToOriginAttrsSQLFunction());
NS_ENSURE_TRUE(convertToOriginAttrs, RESULT_RETRY);
NS_NAMED_LITERAL_CSTRING(convertToOriginAttrsName,
"CONVERT_TO_ORIGIN_ATTRIBUTES");
rv = mDefaultDBState->dbConn->CreateFunction(convertToOriginAttrsName,
2, convertToOriginAttrs);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"INSERT INTO moz_cookies "
"(baseDomain, originAttributes, name, value, host, path, expiry,"
" lastAccessed, creationTime, isSecure, isHttpOnly) "
"SELECT baseDomain, "
" CONVERT_TO_ORIGIN_ATTRIBUTES(appId, inBrowserElement),"
" name, value, host, path, expiry, lastAccessed, creationTime, "
" isSecure, isHttpOnly "
"FROM moz_cookies_old"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->RemoveFunction(convertToOriginAttrsName);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Drop old table
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE moz_cookies_old"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 6"));
}
case 6:
{
// We made a mistake in schema version 6. We cannot remove expected
// columns of any version (checked in the default case) from cookie
// database, because doing this would destroy the possibility of
// downgrading database.
//
// This version simply restores appId and inBrowserElement columns in
// order to fix downgrading issue even though these two columns are no
// longer used in the latest schema.
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_cookies ADD appId INTEGER DEFAULT 0;"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_cookies ADD inBrowserElement INTEGER DEFAULT 0;"));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
// Compute and populate the values of appId and inBrwoserElement from
// originAttributes.
nsCOMPtr<mozIStorageFunction>
setAppId(new SetAppIdFromOriginAttributesSQLFunction());
NS_ENSURE_TRUE(setAppId, RESULT_RETRY);
NS_NAMED_LITERAL_CSTRING(setAppIdName, "SET_APP_ID");
rv = mDefaultDBState->dbConn->CreateFunction(setAppIdName, 1, setAppId);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
nsCOMPtr<mozIStorageFunction>
setInBrowser(new SetInBrowserFromOriginAttributesSQLFunction());
NS_ENSURE_TRUE(setInBrowser, RESULT_RETRY);
NS_NAMED_LITERAL_CSTRING(setInBrowserName, "SET_IN_BROWSER");
rv = mDefaultDBState->dbConn->CreateFunction(setInBrowserName, 1,
setInBrowser);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"UPDATE moz_cookies SET appId = SET_APP_ID(originAttributes), "
"inBrowserElement = SET_IN_BROWSER(originAttributes);"
));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->RemoveFunction(setAppIdName);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
rv = mDefaultDBState->dbConn->RemoveFunction(setInBrowserName);
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
}
// No more upgrades. Update the schema version.
rv = mDefaultDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
@@ -1119,8 +1343,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
"SELECT "
"id, "
"baseDomain, "
"appId, "
"inBrowserElement, "
"originAttributes, "
"name, "
"value, "
"host, "
@@ -1161,8 +1384,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
rv = mDefaultDBState->dbConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_cookies ("
"baseDomain, "
"appId, "
"inBrowserElement, "
"originAttributes, "
"name, "
"value, "
"host, "
@@ -1174,8 +1396,7 @@ nsCookieService::TryInitDB(bool aRecreateDB)
"isHttpOnly"
") VALUES ("
":baseDomain, "
":appId, "
":inBrowserElement, "
":originAttributes, "
":name, "
":value, "
":host, "
@@ -1236,7 +1457,43 @@ nsCookieService::CreateTable()
COOKIES_SCHEMA_VERSION);
if (NS_FAILED(rv)) return rv;
// Create the table. We default appId/inBrowserElement to 0: this is so if
// Create the table.
// We default originAttributes to empty string: this is so if users revert to
// an older Firefox version that doesn't know about this field, any cookies
// set will still work once they upgrade back.
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE moz_cookies ("
"id INTEGER PRIMARY KEY, "
"baseDomain TEXT, "
"originAttributes TEXT NOT NULL DEFAULT '', "
"name TEXT, "
"value TEXT, "
"host TEXT, "
"path TEXT, "
"expiry INTEGER, "
"lastAccessed INTEGER, "
"creationTime INTEGER, "
"isSecure INTEGER, "
"isHttpOnly INTEGER, "
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)"
")"));
if (NS_FAILED(rv)) return rv;
// Create an index on baseDomain.
return mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain, "
"originAttributes)"));
}
// Sets the schema version and creates the moz_cookies table.
nsresult
nsCookieService::CreateTableForSchemaVersion5()
{
// Set the schema version, before creating the table.
nsresult rv = mDefaultDBState->dbConn->SetSchemaVersion(5);
if (NS_FAILED(rv)) return rv;
// Create the table. We default appId/inBrowserElement to 0: this is so if
// users revert to an older Firefox version that doesn't know about these
// fields, any cookies set will still work once they upgrade back.
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
@@ -1590,18 +1847,17 @@ nsCookieService::GetCookieStringCommon(nsIURI *aHostURI,
bool isForeign = true;
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
// Get app info, if channel is present. Else assume default namespace.
uint32_t appId = NECKO_NO_APP_ID;
bool inBrowserElement = false;
// Get originAttributes.
OriginAttributes attrs;
if (aChannel) {
NS_GetAppInfo(aChannel, &appId, &inBrowserElement);
NS_GetOriginAttributes(aChannel, attrs);
}
bool isPrivate = aChannel && NS_UsePrivateBrowsing(aChannel);
nsAutoCString result;
GetCookieStringInternal(aHostURI, isForeign, aHttpBound, appId,
inBrowserElement, isPrivate, result);
GetCookieStringInternal(aHostURI, isForeign, aHttpBound, attrs,
isPrivate, result);
*aCookie = result.IsEmpty() ? nullptr : ToNewCString(result);
return NS_OK;
}
@@ -1664,11 +1920,10 @@ nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
bool isForeign = true;
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
// Get app info, if channel is present. Else assume default namespace.
uint32_t appId = NECKO_NO_APP_ID;
bool inBrowserElement = false;
// Get originAttributes.
OriginAttributes attrs;
if (aChannel) {
NS_GetAppInfo(aChannel, &appId, &inBrowserElement);
NS_GetOriginAttributes(aChannel, attrs);
}
bool isPrivate = aChannel && NS_UsePrivateBrowsing(aChannel);
@@ -1676,21 +1931,20 @@ nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
nsDependentCString cookieString(aCookieHeader);
nsDependentCString serverTime(aServerTime ? aServerTime : "");
SetCookieStringInternal(aHostURI, isForeign, cookieString,
serverTime, aFromHttp, appId, inBrowserElement,
serverTime, aFromHttp, attrs,
isPrivate, aChannel);
return NS_OK;
}
void
nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
bool aIsForeign,
nsDependentCString &aCookieHeader,
const nsCString &aServerTime,
bool aFromHttp,
uint32_t aAppId,
bool aInBrowserElement,
bool aIsPrivate,
nsIChannel *aChannel)
nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
bool aIsForeign,
nsDependentCString &aCookieHeader,
const nsCString &aServerTime,
bool aFromHttp,
const OriginAttributes &aOriginAttrs,
bool aIsPrivate,
nsIChannel *aChannel)
{
NS_ASSERTION(aHostURI, "null host!");
@@ -1711,12 +1965,12 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
nsAutoCString baseDomain;
nsresult rv = GetBaseDomain(aHostURI, baseDomain, requireHostMatch);
if (NS_FAILED(rv)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"couldn't get base domain from URI");
return;
}
nsCookieKey key(baseDomain, aAppId, aInBrowserElement);
nsCookieKey key(baseDomain, aOriginAttrs);
// check default prefs
CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, requireHostMatch,
@@ -1999,9 +2253,9 @@ nsCookieService::Add(const nsACString &aHost,
nsresult
nsCookieService::Remove(const nsACString& aHost, uint32_t aAppId,
bool aInBrowserElement, const nsACString& aName,
const nsACString& aPath, bool aBlocked)
nsCookieService::Remove(const nsACString& aHost, const OriginAttributes& aAttrs,
const nsACString& aName, const nsACString& aPath,
bool aBlocked)
{
if (!mDBState) {
NS_WARNING("No DBState! Profile already closed?");
@@ -2019,7 +2273,7 @@ nsCookieService::Remove(const nsACString& aHost, uint32_t aAppId,
nsListIter matchIter;
RefPtr<nsCookie> cookie;
if (FindCookie(nsCookieKey(baseDomain, aAppId, aInBrowserElement),
if (FindCookie(nsCookieKey(baseDomain, aAttrs),
host,
PromiseFlatCString(aName),
PromiseFlatCString(aPath),
@@ -2057,7 +2311,8 @@ nsCookieService::Remove(const nsACString &aHost,
const nsACString &aPath,
bool aBlocked)
{
return Remove(aHost, NECKO_NO_APP_ID, false, aName, aPath, aBlocked);
OriginAttributes attrs;
return Remove(aHost, attrs, aName, aPath, aBlocked);
}
/******************************************************************************
@@ -2084,8 +2339,7 @@ nsCookieService::Read()
"isSecure, "
"isHttpOnly, "
"baseDomain, "
"appId, "
"inBrowserElement "
"originAttributes "
"FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmtRead));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
@@ -2257,8 +2511,7 @@ nsCookieService::EnsureReadDomain(const nsCookieKey &aKey)
"isHttpOnly "
"FROM moz_cookies "
"WHERE baseDomain = :baseDomain "
" AND appId = :appId "
" AND inBrowserElement = :inBrowserElement"),
" AND originAttributes = :originAttributes"),
getter_AddRefs(mDefaultDBState->stmtReadDomain));
if (NS_FAILED(rv)) {
@@ -2278,13 +2531,12 @@ nsCookieService::EnsureReadDomain(const nsCookieKey &aKey)
rv = mDefaultDBState->stmtReadDomain->BindUTF8StringByName(
NS_LITERAL_CSTRING("baseDomain"), aKey.mBaseDomain);
NS_ASSERT_SUCCESS(rv);
rv = mDefaultDBState->stmtReadDomain->BindInt32ByName(
NS_LITERAL_CSTRING("appId"), aKey.mAppId);
NS_ASSERT_SUCCESS(rv);
rv = mDefaultDBState->stmtReadDomain->BindInt32ByName(
NS_LITERAL_CSTRING("inBrowserElement"), aKey.mInBrowserElement ? 1 : 0);
NS_ASSERT_SUCCESS(rv);
nsAutoCString suffix;
aKey.mOriginAttributes.CreateSuffix(suffix);
rv = mDefaultDBState->stmtReadDomain->BindUTF8StringByName(
NS_LITERAL_CSTRING("originAttributes"), suffix);
NS_ASSERT_SUCCESS(rv);
bool hasResult;
nsCString name, value, host, path;
@@ -2317,8 +2569,8 @@ nsCookieService::EnsureReadDomain(const nsCookieKey &aKey)
COOKIE_LOGSTRING(LogLevel::Debug,
("EnsureReadDomain(): %ld cookies read for base domain %s, "
" appId=%u, inBrowser=%d", array.Length(), aKey.mBaseDomain.get(),
(unsigned)aKey.mAppId, (int)aKey.mInBrowserElement));
" originAttributes = %s", array.Length(), aKey.mBaseDomain.get(),
suffix.get()));
}
void
@@ -2349,8 +2601,7 @@ nsCookieService::EnsureReadComplete()
"isSecure, "
"isHttpOnly, "
"baseDomain, "
"appId, "
"inBrowserElement "
"originAttributes "
"FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmt));
@@ -2364,8 +2615,7 @@ nsCookieService::EnsureReadComplete()
}
nsCString baseDomain, name, value, host, path;
uint32_t appId;
bool inBrowserElement, hasResult;
bool hasResult;
nsAutoTArray<CookieDomainTuple, kMaxNumberOfCookies> array;
while (1) {
rv = stmt->ExecuteStep(&hasResult);
@@ -2383,9 +2633,13 @@ nsCookieService::EnsureReadComplete()
// Make sure we haven't already read the data.
stmt->GetUTF8String(IDX_BASE_DOMAIN, baseDomain);
appId = static_cast<uint32_t>(stmt->AsInt32(IDX_APP_ID));
inBrowserElement = static_cast<bool>(stmt->AsInt32(IDX_BROWSER_ELEM));
nsCookieKey key(baseDomain, appId, inBrowserElement);
nsAutoCString suffix;
OriginAttributes attrs;
stmt->GetUTF8String(IDX_ORIGIN_ATTRIBUTES, suffix);
attrs.PopulateFromSuffix(suffix);
nsCookieKey key(baseDomain, attrs);
if (mDefaultDBState->readSet.GetEntry(key))
continue;
@@ -2529,7 +2783,8 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
if (NS_FAILED(rv))
continue;
// pre-existing cookies have appId=0, inBrowser=false
// pre-existing cookies have appId=0, inBrowser=false set by default
// constructor of OriginAttributes().
nsCookieKey key = DEFAULT_APP_KEY(baseDomain);
// Create a new nsCookie and assign the data. We don't know the cookie
@@ -2620,8 +2875,7 @@ void
nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
bool aIsForeign,
bool aHttpBound,
uint32_t aAppId,
bool aInBrowserElement,
const OriginAttributes aOriginAttrs,
bool aIsPrivate,
nsCString &aCookieString)
{
@@ -2678,7 +2932,7 @@ nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
bool stale = false;
nsCookieKey key(baseDomain, aAppId, aInBrowserElement);
nsCookieKey key(baseDomain, aOriginAttrs);
EnsureReadDomain(key);
// perform the hash lookup
@@ -2878,28 +3132,20 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
return newCookie;
}
// Reject cookie if value contains an RFC 6265 disallowed character.
// See RFC 6265 section 4.1.1
// XXX: For now we allow for web compatibility (see issue #357):
// 0x20 (Space)
// 0x22 (DQUOTE)
// 0x2C (Comma)
// 0x5C (Backslash)
//
// FIXME: Before removing DQUOTE from the exceptions list:
// DQUOTE *cookie-octet DQUOTE is permitted and would fail if just removed.
// This needs better checking for first and last character allowing
// DQUOTE but not in the actual value.
//
// This only applies to cookies set via the Set-Cookie header, since
// document.cookie is defined to be UTF-8.
const char illegalCharacters[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x20, 0x22, */
/* 0x2C, */ 0x3B, /* 0x5C, */ 0x7F, 0x00 };
// reject cookie if value contains an RFC 6265 disallowed character - see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1191423
// NOTE: this is not the full set of characters disallowed by 6265 - notably
// 0x09, 0x20, 0x22, 0x2C, 0x5C, and 0x7F are missing from this list. This is
// for parity with Chrome. This only applies to cookies set via the Set-Cookie
// header, as document.cookie is defined to be UTF-8. Hooray for
// symmetry!</sarcasm>
const char illegalCharacters[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
0x1E, 0x1F, 0x3B, 0x00 };
if (aFromHttp && (cookieAttributes.value.FindCharInSet(illegalCharacters, 0) != -1)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "illegal character in cookie");
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "invalid value character");
return newCookie;
}
@@ -3977,8 +4223,8 @@ nsCookieService::GetCookiesForApp(uint32_t aAppId, bool aOnlyBrowserElement,
for (auto iter = mDBState->hostTable.Iter(); !iter.Done(); iter.Next()) {
nsCookieEntry* entry = iter.Get();
if (entry->mAppId != aAppId ||
(aOnlyBrowserElement && !entry->mInBrowserElement)) {
if (entry->mOriginAttributes.mAppId != aAppId ||
(aOnlyBrowserElement && !entry->mOriginAttributes.mInBrowser)) {
continue;
}
@@ -4030,9 +4276,11 @@ nsCookieService::RemoveCookiesForApp(uint32_t aAppId, bool aOnlyBrowserElement)
//
// NOTE: we could make this better by getting nsCookieEntry objects instead
// of plain nsICookie.
Remove(host, aAppId, true, name, path, false);
OriginAttributes attrs(aAppId, true);
Remove(host, attrs, name, path, false);
if (!aOnlyBrowserElement) {
Remove(host, aAppId, false, name, path, false);
attrs.mInBrowser = false;
Remove(host, attrs, name, path, false);
}
}
@@ -4146,12 +4394,10 @@ bindCookieParameters(mozIStorageBindingParamsArray *aParamsArray,
aKey.mBaseDomain);
NS_ASSERT_SUCCESS(rv);
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("appId"),
aKey.mAppId);
NS_ASSERT_SUCCESS(rv);
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("inBrowserElement"),
aKey.mInBrowserElement ? 1 : 0);
nsAutoCString suffix;
aKey.mOriginAttributes.CreateSuffix(suffix);
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
suffix);
NS_ASSERT_SUCCESS(rv);
rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("name"),
+22 -21
View File
@@ -25,10 +25,15 @@
#include "mozIStorageRow.h"
#include "mozIStorageCompletionCallback.h"
#include "mozIStorageStatementCallback.h"
#include "mozIStorageFunction.h"
#include "nsIVariant.h"
#include "nsIFile.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/MemoryReporting.h"
using mozilla::OriginAttributes;
class nsICookiePermission;
class nsIEffectiveTLDService;
class nsIIDNService;
@@ -60,22 +65,19 @@ public:
nsCookieKey()
{}
nsCookieKey(const nsCString &baseDomain, uint32_t appId, bool inBrowser)
nsCookieKey(const nsCString &baseDomain, const OriginAttributes &attrs)
: mBaseDomain(baseDomain)
, mAppId(appId)
, mInBrowserElement(inBrowser)
, mOriginAttributes(attrs)
{}
explicit nsCookieKey(KeyTypePointer other)
: mBaseDomain(other->mBaseDomain)
, mAppId(other->mAppId)
, mInBrowserElement(other->mInBrowserElement)
, mOriginAttributes(other->mOriginAttributes)
{}
nsCookieKey(KeyType other)
: mBaseDomain(other.mBaseDomain)
, mAppId(other.mAppId)
, mInBrowserElement(other.mInBrowserElement)
, mOriginAttributes(other.mOriginAttributes)
{}
~nsCookieKey()
@@ -84,8 +86,7 @@ public:
bool KeyEquals(KeyTypePointer other) const
{
return mBaseDomain == other->mBaseDomain &&
mAppId == other->mAppId &&
mInBrowserElement == other->mInBrowserElement;
mOriginAttributes == other->mOriginAttributes;
}
static KeyTypePointer KeyToPointer(KeyType aKey)
@@ -98,9 +99,9 @@ public:
// TODO: more efficient way to generate hash?
nsAutoCString temp(aKey->mBaseDomain);
temp.Append('#');
temp.Append(aKey->mAppId);
temp.Append('#');
temp.Append(aKey->mInBrowserElement ? 1 : 0);
nsAutoCString suffix;
aKey->mOriginAttributes.CreateSuffix(suffix);
temp.Append(suffix);
return mozilla::HashString(temp);
}
@@ -108,9 +109,8 @@ public:
enum { ALLOW_MEMMOVE = true };
nsCString mBaseDomain;
uint32_t mAppId;
bool mInBrowserElement;
nsCString mBaseDomain;
OriginAttributes mOriginAttributes;
};
// Inherit from nsCookieKey so this can be stored in nsTHashTable
@@ -274,6 +274,7 @@ class nsCookieService final : public nsICookieService
void InitDBStates();
OpenDBResult TryInitDB(bool aDeleteExistingDB);
nsresult CreateTable();
nsresult CreateTableForSchemaVersion5();
void CloseDBStates();
void CleanupCachedStatements();
void CleanupDefaultDBConnection();
@@ -290,9 +291,9 @@ class nsCookieService final : public nsICookieService
nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch);
nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
nsresult GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie);
void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, uint32_t aAppId, bool aInBrowserElement, bool aIsPrivate, nsCString &aCookie);
void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, const OriginAttributes aOriginAttrs, bool aIsPrivate, nsCString &aCookie);
nsresult SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp);
void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, uint32_t aAppId, bool aInBrowserElement, bool aIsPrivate, nsIChannel* aChannel);
void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, const OriginAttributes &aOriginAttrs, bool aIsPrivate, nsIChannel* aChannel);
bool SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel);
void AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp);
void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr);
@@ -318,12 +319,12 @@ class nsCookieService final : public nsICookieService
/**
* This method is a helper that allows calling nsICookieManager::Remove()
* with appId/inBrowserElement parameters.
* with OriginAttributes parameter.
* NOTE: this could be added to a public interface if we happen to need it.
*/
nsresult Remove(const nsACString& aHost, uint32_t aAppId,
bool aInBrowserElement, const nsACString& aName,
const nsACString& aPath, bool aBlocked);
nsresult Remove(const nsACString& aHost, const OriginAttributes& aAttrs,
const nsACString& aName, const nsACString& aPath,
bool aBlocked);
protected:
// cached members.
+1 -1
View File
@@ -8,7 +8,7 @@
interface nsICookie2;
interface nsIFile;
/**
/**
* Additions to the frozen nsICookieManager
*/
+43 -11
View File
@@ -360,19 +360,19 @@ PackagedAppService::PackagedAppChannelListener::OnStartRequest(nsIRequest *aRequ
// to know if it's a signed package. Notify requesters if it's signed.
if (isFromCache) {
bool isPackageSigned = false;
nsCString signedPackageOrigin;
nsCString signedPackageId;
nsCOMPtr<nsICacheEntry> packageCacheEntry = GetPackageCacheEntry(aRequest);
if (packageCacheEntry) {
const char* key = PackagedAppVerifier::kSignedPakOriginMetadataKey;
const char* key = PackagedAppVerifier::kSignedPakIdMetadataKey;
nsXPIDLCString value;
nsresult rv = packageCacheEntry->GetMetaDataElement(key,
getter_Copies(value));
isPackageSigned = (NS_SUCCEEDED(rv) && !value.IsEmpty());
signedPackageOrigin = value;
signedPackageId = value;
}
if (isPackageSigned) {
LOG(("The cached package is signed. Notify the requesters."));
mDownloader->NotifyOnStartSignedPackageRequest(signedPackageOrigin);
mDownloader->NotifyOnStartSignedPackageRequest(signedPackageId);
}
}
@@ -476,6 +476,12 @@ PackagedAppService::PackagedAppDownloader::OnStartRequest(nsIRequest *aRequest,
NS_WARN_IF(NS_FAILED(rv));
EnsureVerifier(aRequest);
if (!mVerifier->WouldVerify()) {
// It means there's no signature or the signed app is disabled.
return NS_OK;
}
mVerifier->OnStartRequest(nullptr, uri);
// Since the header is considered as a part of the streaming data,
@@ -635,7 +641,7 @@ PackagedAppService::PackagedAppDownloader::OnStopRequest(nsIRequest *aRequest,
// Chances to get here:
// 1) Very likely the package has been cached or
// 2) Less likely the package is malformed.
if (!mVerifier) {
if (!mVerifier || !mVerifier->WouldVerify()) {
FinalizeDownload(aStatusCode);
} else {
// We've got a broken last part and some resources might be still
@@ -671,6 +677,12 @@ PackagedAppService::PackagedAppDownloader::OnStopRequest(nsIRequest *aRequest,
RefPtr<ResourceCacheInfo> info =
new ResourceCacheInfo(uri, entry, aStatusCode, lastPart);
if (!mVerifier->WouldVerify()) {
// No manifest at all. Everything is simply a resource.
OnResourceVerified(info, true);
return NS_OK;
}
mVerifier->OnStopRequest(nullptr, info, aStatusCode);
return NS_OK;
@@ -699,6 +711,11 @@ PackagedAppService::PackagedAppDownloader::ConsumeData(nsIInputStream *aStream,
self->mWriter->ConsumeData(aFromRawSegment, aCount, aWriteCount);
if (!self->mVerifier->WouldVerify()) {
// No signature or signed app support is disabled.
return NS_OK;
}
nsCOMPtr<nsIInputStream> stream = CreateSharedStringStream(aFromRawSegment, aCount);
return self->mVerifier->OnDataAvailable(nullptr, nullptr, stream, 0, aCount);
}
@@ -742,7 +759,7 @@ PackagedAppService::PackagedAppDownloader::AddCallback(nsIURI *aURI,
if (mVerifier && mVerifier->GetIsPackageSigned()) {
// TODO: Bug 1178526 will deal with the package identifier things.
// For now we just use the origin as the identifier.
listener->OnStartSignedPackageRequest(mVerifier->GetPackageOrigin());
listener->OnStartSignedPackageRequest(mVerifier->GetPackageIdentifier());
listener = nullptr; // So that the request will not be added to the queue.
}
mCacheStorage->AsyncOpenURI(aURI, EmptyCString(),
@@ -876,7 +893,24 @@ PackagedAppService::PackagedAppDownloader::NotifyOnStartSignedPackageRequest(con
mRequesters.Clear();
}
void PackagedAppService::PackagedAppDownloader::InstallSignedPackagedApp()
static bool
AddPackageIdToOrigin(nsACString& aOrigin, const nsACString& aPackageId)
{
nsAutoCString originNoSuffix;
mozilla::OriginAttributes attrs;
if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) {
return false;
}
attrs.mSignedPkg = NS_ConvertUTF8toUTF16(aPackageId);
nsAutoCString suffixWithPackageId;
attrs.CreateSuffix(suffixWithPackageId);
aOrigin = originNoSuffix + suffixWithPackageId;
return true;
}
void
PackagedAppService::PackagedAppDownloader::InstallSignedPackagedApp()
{
// TODO: Bug 1178533 to register permissions, system messages etc on navigation to
// signed packages.
@@ -935,9 +969,7 @@ PackagedAppService::PackagedAppDownloader::OnManifestVerified(const ResourceCach
return;
}
nsCString packageOrigin;
mVerifier->GetPackageOrigin(packageOrigin);
NotifyOnStartSignedPackageRequest(packageOrigin);
NotifyOnStartSignedPackageRequest(mVerifier->GetPackageIdentifier());
InstallSignedPackagedApp();
}
@@ -955,7 +987,7 @@ PackagedAppService::PackagedAppDownloader::OnResourceVerified(const ResourceCach
if (mVerifier->GetIsPackageSigned()) {
// TODO: Bug 1178526 will deal with the package identifier things.
// For now we just use the origin as the identifier.
NotifyOnStartSignedPackageRequest(mVerifier->GetPackageOrigin());
NotifyOnStartSignedPackageRequest(mVerifier->GetPackageIdentifier());
}
// Serve this resource to all listeners.
+5 -3
View File
@@ -29,7 +29,7 @@ PackagedAppUtils.prototype = {
classDescription: "Packaged App Utils",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPackagedAppUtils]),
verifyManifest: function(aHeader, aManifest, aCallback) {
verifyManifest: function(aHeader, aManifest, aCallback, aDeveloperMode) {
debug("Manifest: " + aManifest);
// parse signature from header
@@ -83,8 +83,10 @@ PackagedAppUtils.prototype = {
throw "CERTDB_ERROR";
}
certDb.verifySignedManifestAsync(
Ci.nsIX509CertDB.PrivilegedPackageRoot, manifestStream, signatureStream,
let trustedRoot = aDeveloperMode ? Ci.nsIX509CertDB.DeveloperImportedRoot
: Ci.nsIX509CertDB.PrivilegedPackageRoot;
certDb.verifySignedManifestAsync(trustedRoot, manifestStream, signatureStream,
function(aRv, aCert) {
aCallback.fireVerifiedEvent(true, Components.isSuccessCode(aRv));
});
+48 -22
View File
@@ -16,12 +16,13 @@
#include "mozilla/Preferences.h"
#include "nsIPackagedAppUtils.h"
#include "nsIInputStream.h"
#include "nsComponentManagerUtils.h"
#include "nsIURL.h"
#include "mozilla/BasePrincipal.h"
static const short kResourceHashType = nsICryptoHash::SHA256;
// If it's true, all the verification will be skipped and the package will
// be treated signed.
static bool gDeveloperMode = false;
static bool gSignedAppEnabled = false;
namespace mozilla {
namespace net {
@@ -32,7 +33,7 @@ NS_IMPL_ISUPPORTS(PackagedAppVerifier, nsIPackagedAppVerifier, nsIVerificationCa
NS_IMPL_ISUPPORTS(PackagedAppVerifier::ResourceCacheInfo, nsISupports)
const char* PackagedAppVerifier::kSignedPakOriginMetadataKey = "signed-pak-origin";
const char* PackagedAppVerifier::kSignedPakIdMetadataKey = "package-id";
PackagedAppVerifier::PackagedAppVerifier()
{
@@ -67,18 +68,23 @@ NS_IMETHODIMP PackagedAppVerifier::Init(nsIPackagedAppVerifierListener* aListene
{
static bool onceThru = false;
if (!onceThru) {
Preferences::AddBoolVarCache(&gDeveloperMode,
"network.http.packaged-apps-developer-mode", false);
Preferences::AddBoolVarCache(&gSignedAppEnabled,
"network.http.signed-packages.enabled", false);
onceThru = true;
}
mListener = aListener;
mState = STATE_UNKNOWN;
mPackageOrigin = aPackageOrigin;
mSignature = aSignature;
mIsPackageSigned = false;
mPackageCacheEntry = aPackageCacheEntry;
mIsFirstResource = true;
mManifest = EmptyCString();
nsAutoCString originNoSuffix;
OriginAttributes().PopulateFromOrigin(aPackageOrigin, originNoSuffix);
mBypassVerification = (originNoSuffix ==
Preferences::GetCString("network.http.signed-packages.trusted-origin"));
nsresult rv;
mPackagedAppUtils = do_CreateInstance(NS_PACKAGEDAPPUTILS_CONTRACTID, &rv);
@@ -127,7 +133,7 @@ PackagedAppVerifier::WriteManifest(nsIInputStream* aStream,
uint32_t* aWriteCount)
{
LOG(("WriteManifest: length %u", aCount));
LOG(("%s", aFromRawSegment));
LOG(("%s", nsCString(aFromRawSegment, aCount).get()));
nsCString* manifest = static_cast<nsCString*>(aManifest);
manifest->AppendASCII(aFromRawSegment, aCount);
*aWriteCount = aCount;
@@ -268,12 +274,6 @@ PackagedAppVerifier::VerifyManifest(const ResourceCacheInfo* aInfo)
mState = STATE_MANIFEST_VERIFYING;
if (gDeveloperMode) {
LOG(("Developer mode! Bypass verification."));
FireVerifiedEvent(true, true);
return;
}
if (mSignature.IsEmpty()) {
LOG(("No signature. No need to do verification."));
FireVerifiedEvent(true, true);
@@ -282,7 +282,11 @@ PackagedAppVerifier::VerifyManifest(const ResourceCacheInfo* aInfo)
LOG(("Signature: length = %u\n%s", mSignature.Length(), mSignature.get()));
LOG(("Manifest: length = %u\n%s", mManifest.Length(), mManifest.get()));
nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest, this);
bool useDeveloperRoot =
!Preferences::GetCString("network.http.signed-packages.developer-root").IsEmpty();
nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest,
this, useDeveloperRoot);
if (NS_FAILED(rv)) {
LOG(("VerifyManifest FAILED rv = %u", (unsigned)rv));
}
@@ -309,8 +313,8 @@ PackagedAppVerifier::VerifyResource(const ResourceCacheInfo* aInfo)
MOZ_CRASH();
}
if (gDeveloperMode) {
LOG(("Developer mode! Bypass integrity check."));
if (mBypassVerification) {
LOG(("Origin is trusted. Bypass integrity check."));
FireVerifiedEvent(false, true);
return;
}
@@ -349,6 +353,12 @@ PackagedAppVerifier::OnManifestVerified(bool aSuccess)
return;
}
if (!aSuccess && mBypassVerification) {
aSuccess = true;
LOG(("Developer mode! Treat junk signature valid."));
}
// Only when the manifest verified and package has signature would we
// regard this package is signed.
mIsPackageSigned = aSuccess && !mSignature.IsEmpty();
@@ -356,14 +366,24 @@ PackagedAppVerifier::OnManifestVerified(bool aSuccess)
mState = aSuccess ? STATE_MANIFEST_VERIFIED_OK
: STATE_MANIFEST_VERIFIED_FAILED;
// TODO: Update mPackageOrigin.
// Obtain the package identifier from manifest if the package is signed.
if (mIsPackageSigned) {
mPackagedAppUtils->GetPackageIdentifier(mPackageIdentifer);
LOG(("PackageIdentifer is: %s", mPackageIdentifer.get()));
}
// If the signature verification failed, doom the package cache to
// make its subresources unavailable in the subsequent requests.
if (!aSuccess && mPackageCacheEntry) {
mPackageCacheEntry->AsyncDoom(nullptr);
}
// If the package is signed, add related info to the package cache.
if (mIsPackageSigned && mPackageCacheEntry) {
LOG(("This package is signed. Add this info to the cache channel."));
if (mPackageCacheEntry) {
mPackageCacheEntry->SetMetaDataElement(kSignedPakOriginMetadataKey,
mPackageOrigin.get());
mPackageCacheEntry->SetMetaDataElement(kSignedPakIdMetadataKey,
mPackageIdentifer.get());
mPackageCacheEntry = nullptr; // the cache entry is no longer needed.
}
}
@@ -418,14 +438,20 @@ PackagedAppVerifier::SetHasBrokenLastPart(nsresult aStatusCode)
mPendingResourceCacheInfoList.insertBack(info);
}
bool
PackagedAppVerifier::WouldVerify() const
{
return gSignedAppEnabled && !mSignature.IsEmpty();
}
//---------------------------------------------------------------
// nsIPackagedAppVerifier.
//---------------------------------------------------------------
NS_IMETHODIMP
PackagedAppVerifier::GetPackageOrigin(nsACString& aPackageOrigin)
PackagedAppVerifier::GetPackageIdentifier(nsACString& aPackageIdentifier)
{
aPackageOrigin = mPackageOrigin;
aPackageIdentifier = mPackageIdentifer;
return NS_OK;
}
+10 -3
View File
@@ -109,12 +109,14 @@ public:
return mIsPackageSigned;
}
const nsACString& GetPackageOrigin() const
const nsACString& GetPackageIdentifier() const
{
return mPackageOrigin;
return mPackageIdentifer;
}
static const char* kSignedPakOriginMetadataKey;
bool WouldVerify() const;
static const char* kSignedPakIdMetadataKey;
private:
virtual ~PackagedAppVerifier();
@@ -169,6 +171,9 @@ private:
// Whether this package app is signed.
bool mIsPackageSigned;
// Whether we should bypass verification.
bool mBypassVerification;
// The package cache entry (e.g. http://foo.com/app.pak) used to store
// any necessarry signed package information.
nsCOMPtr<nsICacheEntry> mPackageCacheEntry;
@@ -191,6 +196,8 @@ private:
// A place to store the computed hashes of each resource.
nsClassHashtable<nsCStringHashKey, nsCString> mResourceHashStore;
nsCString mPackageIdentifer;
}; // class PackagedAppVerifier
} // namespace net
+43 -53
View File
@@ -16,18 +16,17 @@
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "mozilla/DebugOnly.h"
#include "nsNetUtil.h"
namespace mozilla {
namespace net {
static inline void
GetAuthKey(const char *scheme, const char *host, int32_t port, uint32_t appId, bool inBrowserElement, nsCString &key)
GetAuthKey(const char *scheme, const char *host, int32_t port, nsACString const &originSuffix, nsCString &key)
{
key.Truncate();
key.AppendInt(appId);
key.Append(':');
key.AppendInt(inBrowserElement);
key.Append(originSuffix);
key.Append(':');
key.Append(scheme);
key.AppendLiteral("://");
@@ -57,11 +56,11 @@ StrEquivalent(const char16_t *a, const char16_t *b)
nsHttpAuthCache::nsHttpAuthCache()
: mDB(nullptr)
, mObserver(new AppDataClearObserver(this))
, mObserver(new OriginClearObserver(this))
{
nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
if (obsSvc) {
obsSvc->AddObserver(mObserver, "webapps-clear-data", false);
obsSvc->AddObserver(mObserver, "clear-origin-data", false);
}
}
@@ -71,7 +70,7 @@ nsHttpAuthCache::~nsHttpAuthCache()
ClearAll();
nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
if (obsSvc) {
obsSvc->RemoveObserver(mObserver, "webapps-clear-data");
obsSvc->RemoveObserver(mObserver, "clear-origin-data");
mObserver->mOwner = nullptr;
}
}
@@ -97,15 +96,14 @@ nsHttpAuthCache::GetAuthEntryForPath(const char *scheme,
const char *host,
int32_t port,
const char *path,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsHttpAuthEntry **entry)
{
LOG(("nsHttpAuthCache::GetAuthEntryForPath [key=%s://%s:%d path=%s]\n",
scheme, host, port, path));
nsAutoCString key;
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, originSuffix, key);
if (!node)
return NS_ERROR_NOT_AVAILABLE;
@@ -118,8 +116,7 @@ nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
const char *host,
int32_t port,
const char *realm,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsHttpAuthEntry **entry)
{
@@ -127,7 +124,7 @@ nsHttpAuthCache::GetAuthEntryForDomain(const char *scheme,
scheme, host, port, realm));
nsAutoCString key;
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, originSuffix, key);
if (!node)
return NS_ERROR_NOT_AVAILABLE;
@@ -143,8 +140,7 @@ nsHttpAuthCache::SetAuthEntry(const char *scheme,
const char *realm,
const char *creds,
const char *challenge,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
const nsHttpAuthIdentity *ident,
nsISupports *metadata)
{
@@ -159,7 +155,7 @@ nsHttpAuthCache::SetAuthEntry(const char *scheme,
}
nsAutoCString key;
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, appId, inBrowserElement, key);
nsHttpAuthNode *node = LookupAuthNode(scheme, host, port, originSuffix, key);
if (!node) {
// create a new entry node and set the given entry
@@ -182,14 +178,13 @@ nsHttpAuthCache::ClearAuthEntry(const char *scheme,
const char *host,
int32_t port,
const char *realm,
uint32_t appId,
bool inBrowserElement)
nsACString const &originSuffix)
{
if (!mDB)
return;
nsAutoCString key;
GetAuthKey(scheme, host, port, appId, inBrowserElement, key);
GetAuthKey(scheme, host, port, originSuffix, key);
PL_HashTableRemove(mDB, key.get());
}
@@ -213,14 +208,13 @@ nsHttpAuthNode *
nsHttpAuthCache::LookupAuthNode(const char *scheme,
const char *host,
int32_t port,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsCString &key)
{
if (!mDB)
return nullptr;
GetAuthKey(scheme, host, port, appId, inBrowserElement, key);
GetAuthKey(scheme, host, port, originSuffix, key);
return (nsHttpAuthNode *) PL_HashTableLookup(mDB, key.get());
}
@@ -268,60 +262,56 @@ PLHashAllocOps nsHttpAuthCache::gHashAllocOps =
nsHttpAuthCache::FreeEntry
};
NS_IMPL_ISUPPORTS(nsHttpAuthCache::AppDataClearObserver, nsIObserver)
NS_IMPL_ISUPPORTS(nsHttpAuthCache::OriginClearObserver, nsIObserver)
NS_IMETHODIMP
nsHttpAuthCache::AppDataClearObserver::Observe(nsISupports *subject,
const char * topic,
const char16_t * data_unicode)
nsHttpAuthCache::OriginClearObserver::Observe(nsISupports *subject,
const char * topic,
const char16_t * data_unicode)
{
NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(subject);
if (!params) {
NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
return NS_ERROR_UNEXPECTED;
OriginAttributesPattern pattern;
if (!pattern.Init(nsDependentString(data_unicode))) {
NS_ERROR("Cannot parse origin attributes pattern");
return NS_ERROR_FAILURE;
}
uint32_t appId;
bool browserOnly;
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID);
mOwner->ClearAppData(appId, browserOnly);
mOwner->ClearOriginData(pattern);
return NS_OK;
}
static int
RemoveEntriesForApp(PLHashEntry *entry, int32_t number, void *arg)
RemoveEntriesForPattern(PLHashEntry *entry, int32_t number, void *arg)
{
nsDependentCString key(static_cast<const char*>(entry->key));
nsAutoCString* prefix = static_cast<nsAutoCString*>(arg);
if (StringBeginsWith(key, *prefix)) {
// Extract the origin attributes suffix from the key.
int32_t colon = key.Find(NS_LITERAL_CSTRING(":"));
MOZ_ASSERT(colon != kNotFound);
nsDependentCSubstring oaSuffix;
oaSuffix.Rebind(key.BeginReading(), colon);
// Build the OriginAttributes object of it...
OriginAttributes oa;
DebugOnly<bool> rv = oa.PopulateFromSuffix(oaSuffix);
MOZ_ASSERT(rv);
// ...and match it against the given pattern.
OriginAttributesPattern const *pattern = static_cast<OriginAttributesPattern const*>(arg);
if (pattern->Matches(oa)) {
return HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE;
}
return HT_ENUMERATE_NEXT;
}
void
nsHttpAuthCache::ClearAppData(uint32_t appId, bool browserOnly)
nsHttpAuthCache::ClearOriginData(OriginAttributesPattern const &pattern)
{
if (!mDB) {
return;
}
nsAutoCString keyPrefix;
keyPrefix.AppendInt(appId);
keyPrefix.Append(':');
if (browserOnly) {
keyPrefix.AppendInt(browserOnly);
keyPrefix.Append(':');
}
PL_HashTableEnumerateEntries(mDB, RemoveEntriesForApp, &keyPrefix);
PL_HashTableEnumerateEntries(mDB, RemoveEntriesForPattern, (void*)&pattern);
}
//-----------------------------------------------------------------------------
+13 -15
View File
@@ -16,6 +16,9 @@
class nsCString;
namespace mozilla {
class OriginAttributesPattern;
namespace net {
struct nsHttpAuthPath {
@@ -181,8 +184,7 @@ public:
const char *host,
int32_t port,
const char *path,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsHttpAuthEntry **entry);
// |scheme|, |host|, and |port| are required
@@ -192,8 +194,7 @@ public:
const char *host,
int32_t port,
const char *realm,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsHttpAuthEntry **entry);
// |scheme|, |host|, and |port| are required
@@ -208,8 +209,7 @@ public:
const char *realm,
const char *credentials,
const char *challenge,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
const nsHttpAuthIdentity *ident,
nsISupports *metadata);
@@ -217,8 +217,7 @@ public:
const char *host,
int32_t port,
const char *realm,
uint32_t appId,
bool inBrowserElement);
nsACString const &originSuffix);
// expire all existing auth list entries including proxy auths.
nsresult ClearAll();
@@ -227,8 +226,7 @@ private:
nsHttpAuthNode *LookupAuthNode(const char *scheme,
const char *host,
int32_t port,
uint32_t appId,
bool inBrowserElement,
nsACString const &originSuffix,
nsCString &key);
// hash table allocation functions
@@ -239,20 +237,20 @@ private:
static PLHashAllocOps gHashAllocOps;
class AppDataClearObserver : public nsIObserver {
virtual ~AppDataClearObserver() {}
class OriginClearObserver : public nsIObserver {
virtual ~OriginClearObserver() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
explicit AppDataClearObserver(nsHttpAuthCache* aOwner) : mOwner(aOwner) {}
explicit OriginClearObserver(nsHttpAuthCache* aOwner) : mOwner(aOwner) {}
nsHttpAuthCache* mOwner;
};
void ClearAppData(uint32_t appId, bool browserOnly);
void ClearOriginData(OriginAttributesPattern const &pattern);
private:
PLHashTable *mDB; // "host:port" --> nsHttpAuthNode
RefPtr<AppDataClearObserver> mObserver;
RefPtr<OriginClearObserver> mObserver;
};
} // namespace net
+9 -11
View File
@@ -67,11 +67,10 @@ nsHttpAuthManager::GetAuthIdentity(const nsACString & aScheme,
nsHttpAuthCache* auth_cache = aIsPrivate ? mPrivateAuthCache : mAuthCache;
nsHttpAuthEntry * entry = nullptr;
nsresult rv;
uint32_t appId = NECKO_NO_APP_ID;
bool inBrowserElement = false;
nsAutoCString originSuffix;
if (aPrincipal) {
appId = aPrincipal->GetAppId();
inBrowserElement = aPrincipal->GetIsInBrowserElement();
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(originSuffix);
}
if (!aPath.IsEmpty())
@@ -79,14 +78,14 @@ nsHttpAuthManager::GetAuthIdentity(const nsACString & aScheme,
PromiseFlatCString(aHost).get(),
aPort,
PromiseFlatCString(aPath).get(),
appId, inBrowserElement,
originSuffix,
&entry);
else
rv = auth_cache->GetAuthEntryForDomain(PromiseFlatCString(aScheme).get(),
PromiseFlatCString(aHost).get(),
aPort,
PromiseFlatCString(aRealm).get(),
appId, inBrowserElement,
originSuffix,
&entry);
if (NS_FAILED(rv))
@@ -117,13 +116,12 @@ nsHttpAuthManager::SetAuthIdentity(const nsACString & aScheme,
PromiseFlatString(aUserName).get(),
PromiseFlatString(aUserPassword).get());
uint32_t appId = NECKO_NO_APP_ID;
bool inBrowserElement = false;
nsAutoCString originSuffix;
if (aPrincipal) {
appId = aPrincipal->GetAppId();
inBrowserElement = aPrincipal->GetIsInBrowserElement();
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(originSuffix);
}
nsHttpAuthCache* auth_cache = aIsPrivate ? mPrivateAuthCache : mAuthCache;
return auth_cache->SetAuthEntry(PromiseFlatCString(aScheme).get(),
PromiseFlatCString(aHost).get(),
@@ -132,7 +130,7 @@ nsHttpAuthManager::SetAuthIdentity(const nsACString & aScheme,
PromiseFlatCString(aRealm).get(),
nullptr, // credentials
nullptr, // challenge
appId, inBrowserElement,
originSuffix,
&ident,
nullptr); // metadata
}
@@ -43,19 +43,16 @@ namespace net {
#define MAX_DISPLAYED_HOST_LENGTH 64
static void
GetAppIdAndBrowserStatus(nsIChannel* aChan, uint32_t* aAppId, bool* aInBrowserElem)
GetOriginAttributesSuffix(nsIChannel* aChan, nsACString &aSuffix)
{
nsCOMPtr<nsILoadContext> loadContext;
OriginAttributes oa;
// Deliberately ignoring the result and going with defaults
if (aChan) {
NS_QueryNotificationCallbacks(aChan, loadContext);
}
if (!loadContext) {
*aAppId = NECKO_NO_APP_ID;
*aInBrowserElem = false;
} else {
loadContext->GetAppId(aAppId);
loadContext->GetIsInBrowserElement(aInBrowserElem);
NS_GetOriginAttributes(aChan, oa);
}
oa.CreateSuffix(aSuffix);
}
nsHttpChannelAuthProvider::nsHttpChannelAuthProvider()
@@ -77,15 +74,15 @@ nsHttpChannelAuthProvider::~nsHttpChannelAuthProvider()
}
uint32_t nsHttpChannelAuthProvider::sAuthAllowPref =
SUBRESOURCE_AUTH_DIALOG_DISALLOW_CROSS_ORIGIN;
SUBRESOURCE_AUTH_DIALOG_ALLOW_ALL;
void
nsHttpChannelAuthProvider::InitializePrefs()
{
MOZ_ASSERT(NS_IsMainThread());
mozilla::Preferences::AddUintVarCache(&sAuthAllowPref,
"network.auth.allow-subresource-auth",
SUBRESOURCE_AUTH_DIALOG_DISALLOW_CROSS_ORIGIN);
"network.auth.subresource-http-auth-allow",
SUBRESOURCE_AUTH_DIALOG_ALLOW_ALL);
}
NS_IMETHODIMP
@@ -404,9 +401,8 @@ nsHttpChannelAuthProvider::GenCredsAndSetEntry(nsIHttpAuthenticator *auth,
nsHttpAuthCache *authCache = gHttpHandler->AuthCache(mIsPrivate);
nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
uint32_t appId;
bool isInBrowserElement;
GetAppIdAndBrowserStatus(chan, &appId, &isInBrowserElement);
nsAutoCString suffix;
GetOriginAttributesSuffix(chan, suffix);
// create a cache entry. we do this even though we don't yet know that
// these credentials are valid b/c we need to avoid prompting the user
@@ -417,7 +413,7 @@ nsHttpChannelAuthProvider::GenCredsAndSetEntry(nsIHttpAuthenticator *auth,
rv = authCache->SetAuthEntry(scheme, host, port, directory, realm,
saveCreds ? *result : nullptr,
saveChallenge ? challenge : nullptr,
appId, isInBrowserElement,
suffix,
saveIdentity ? &ident : nullptr,
sessionState);
return rv;
@@ -678,9 +674,8 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
}
nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
uint32_t appId;
bool isInBrowserElement;
GetAppIdAndBrowserStatus(chan, &appId, &isInBrowserElement);
nsAutoCString suffix;
GetOriginAttributesSuffix(chan, suffix);
//
// if we already tried some credentials for this transaction, then
@@ -690,8 +685,7 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
//
nsHttpAuthEntry *entry = nullptr;
authCache->GetAuthEntryForDomain(scheme.get(), host, port,
realm.get(), appId,
isInBrowserElement, &entry);
realm.get(), suffix, &entry);
// hold reference to the auth session state (in case we clear our
// reference to the entry).
@@ -722,7 +716,7 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
// corresponding entry from the auth cache.
authCache->ClearAuthEntry(scheme.get(), host,
port, realm.get(),
appId, isInBrowserElement);
suffix);
entry = nullptr;
ident->Clear();
}
@@ -1107,15 +1101,13 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthAvailable(nsISupports *aContext,
ParseRealm(mCurrentChallenge.get(), realm);
nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
uint32_t appId;
bool isInBrowserElement;
GetAppIdAndBrowserStatus(chan, &appId, &isInBrowserElement);
nsAutoCString suffix;
GetOriginAttributesSuffix(chan, suffix);
nsHttpAuthCache *authCache = gHttpHandler->AuthCache(mIsPrivate);
nsHttpAuthEntry *entry = nullptr;
authCache->GetAuthEntryForDomain(scheme.get(), host, port,
realm.get(), appId,
isInBrowserElement,
realm.get(), suffix,
&entry);
nsCOMPtr<nsISupports> sessionStateGrip;
@@ -1365,12 +1357,11 @@ nsHttpChannelAuthProvider::SetAuthorizationHeader(nsHttpAuthCache *authCache,
}
nsCOMPtr<nsIChannel> chan = do_QueryInterface(mAuthChannel);
uint32_t appId;
bool isInBrowserElement;
GetAppIdAndBrowserStatus(chan, &appId, &isInBrowserElement);
nsAutoCString suffix;
GetOriginAttributesSuffix(chan, suffix);
rv = authCache->GetAuthEntryForPath(scheme, host, port, path,
appId, isInBrowserElement, &entry);
suffix, &entry);
if (NS_SUCCEEDED(rv)) {
// if we are trying to add a header for origin server auth and if the
// URL contains an explicit username, then try the given username first.
@@ -5,33 +5,79 @@ var Cu = Components.utils;
function handleRequest(request, response)
{
response.setHeader("Content-Type", "application/package", false);
response.write(octetStreamData.packageHeader + octetStreamData.getData());
response.write(signedPackage);
return;
}
// The package content
// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
var octetStreamData = {
packageHeader: 'manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n',
content: [
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script> alert('OK: hello'); alert('DONE'); </script>\r\n</head>\r\n Web Packaged App Index\r\n</html>\r\n", type: "text/html" },
{ headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
{ headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
],
token : "gc0pJq0M:08jU534c0p",
getData: function() {
var str = "";
for (var i in this.content) {
str += "--" + this.token + "\r\n";
for (var j in this.content[i].headers) {
str += this.content[i].headers[j] + "\r\n";
}
str += "\r\n";
str += this.content[i].data + "\r\n";
}
str += "--" + this.token + "--";
return str;
}
}
var signedPackage = [
"manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r",
"--7B0MKBI3UH\r",
"Content-Location: manifest.webapp\r",
"Content-Type: application/x-web-app-manifest+json\r",
"\r",
"{",
" \"name\": \"My App\",",
" \"moz-resources\": [",
" {",
" \"src\": \"page2.html\",",
" \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"",
" },",
" {",
" \"src\": \"index.html\",",
" \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"",
" },",
" {",
" \"src\": \"scripts/script.js\",",
" \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"",
" },",
" {",
" \"src\": \"scripts/library.js\",",
" \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"",
" }",
" ],",
" \"moz-permissions\": [",
" {",
" \"systemXHR\": {",
" \"description\": \"Needed to download stuff\"",
" },",
" \"devicestorage:pictures\": {",
" \"description\": \"Need to load pictures\"",
" }",
" }",
" ],",
" \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",",
" \"moz-package-location\": \"https://example.com/myapp/app.pak\",",
" \"description\": \"A great app!\"",
"}\r",
"--7B0MKBI3UH\r",
"Content-Location: page2.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" page2.html",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: index.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" Last updated: 2015/10/01 14:10 PST",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/script.js\r",
"Content-Type: text/javascript\r",
"\r",
"// script.js",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/library.js\r",
"Content-Type: text/javascript\r",
"\r",
"// library.js",
"\r",
"--7B0MKBI3UH--"
].join("\n");
@@ -21,8 +21,8 @@ var Cr = SpecialPowers.Cr;
SpecialPowers.pushPrefEnv(
{ "set": [["network.http.enable-packaged-apps", true],
["network.http.packaged-apps-developer-mode", true],
["dom.ipc.processPriorityManager.testMode", true],
["network.http.signed-packages.enabled", true],
["dom.ipc.processPriorityManager.enabled", true],
["dom.ipc.tabs.disabled", false],
["dom.ipc.processCount", 3],
+1 -1
View File
@@ -34,7 +34,7 @@ function launchConnection(socks_vers, socks_port, dest_host, dest_port, dns)
output.close();
}
for each (var arg in arguments) {
for (var arg of arguments) {
print('client: running test', arg);
test = arg.split('|');
launchConnection(test[0], parseInt(test[1]), test[2],
@@ -1,5 +1,5 @@
// This file tests authentication prompt depending on pref
// network.auth.allow-subresource-auth:
// network.auth.subresource-http-auth-allow:
// 0 - don't allow sub-resources to open HTTP authentication credentials
// dialogs
// 1 - allow sub-resources to open HTTP authentication credentials dialogs,
@@ -131,9 +131,9 @@ function makeChan(loadingUrl, url, contentPolicy) {
return chan;
}
function Test(allow_subresource_auth_pref, loadingUri, uri, contentPolicy,
function Test(subresource_http_auth_allow_pref, loadingUri, uri, contentPolicy,
expectedCode) {
this._allow_subresource_auth_pref = allow_subresource_auth_pref;
this._subresource_http_auth_allow_pref = subresource_http_auth_allow_pref;
this._loadingUri = loadingUri;
this._uri = uri;
this._contentPolicy = contentPolicy;
@@ -141,7 +141,7 @@ function Test(allow_subresource_auth_pref, loadingUri, uri, contentPolicy,
}
Test.prototype = {
_allow_subresource_auth_pref: 1,
_subresource_http_auth_allow_pref: 1,
_loadingUri: null,
_uri: null,
_contentPolicy: Ci.nsIContentPolicy.TYPE_OTHER,
@@ -184,14 +184,14 @@ Test.prototype = {
},
run: function() {
dump("Run test: " + this._allow_subresource_auth_pref
dump("Run test: " + this._subresource_http_auth_allow_pref
+ this._loadingUri
+ this._uri
+ this._contentPolicy
+ this._expectedCode + " \n");
prefs.setIntPref("network.auth.allow-subresource-auth",
this._allow_subresource_auth_pref);
prefs.setIntPref("network.auth.subresource-http-auth-allow",
this._subresource_http_auth_allow_pref);
let chan = makeChan(this._loadingUri, this._uri, this._contentPolicy);
chan.notificationCallbacks = new Requestor(this._expectedCode == 200);
chan.asyncOpen(this, null);
+2 -6
View File
@@ -23,12 +23,8 @@ function run_test() {
am.setAuthIdentity("http", "a.example.com", -1, "basic", "realm", "", "example.com", "user3", "pass3", false, app1browser);
am.setAuthIdentity("http", "a.example.com", -1, "basic", "realm", "", "example.com", "user2", "pass2", false, app10);
let subject = {
appId: 1,
browserOnly: true,
QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
};
Services.obs.notifyObservers(subject, "webapps-clear-data", null);
let attrs_inBrowser = JSON.stringify({ appId:1, inBrowser:true });
Services.obs.notifyObservers(null, "clear-origin-data", attrs_inBrowser);
var domain = {value: ""}, user = {value: ""}, pass = {value: ""};
try {
+1 -1
View File
@@ -245,7 +245,7 @@ function run_test() {
prefs.setIntPref("network.proxy.type", 1);
// Turn off the authentication dialog blocking for this test.
prefs.setIntPref("network.auth.allow-subresource-auth", 2);
prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
tests[current_test]();
}
+1 -1
View File
@@ -7,7 +7,7 @@ Cu.import("resource://gre/modules/Services.jsm");
// Turn off the authentication dialog blocking for this test.
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
prefs.setIntPref("network.auth.allow-subresource-auth", 2);
prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
XPCOMUtils.defineLazyGetter(this, "URL", function() {
return "http://localhost:" + httpserv.identity.primaryPort;
+1 -1
View File
@@ -35,7 +35,7 @@ function check_for_exception(spec)
}
function run_test() {
for each (spec in specs) {
for (var spec of specs) {
check_for_exception(spec);
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
for each (spec in specs) {
for (var spec of specs) {
var uri = ios.newURI(spec, null, null);
if (uri.spec.indexOf("..") != -1)
do_throw("resource: traversal remains: '"+spec+"' ==> '"+uri.spec+"'");
+2 -2
View File
@@ -43,7 +43,7 @@ function run_test() {
// Make sure our prefs are set such that this test actually means something
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
for each (var pref in prefData) {
for (var pref of prefData) {
try {
pref.oldVal = prefs.getBoolPref(pref.name);
} catch(e) {
@@ -63,7 +63,7 @@ function run_test() {
do_check_eq(uri4.host, uri5.host);
do_check_eq(uri4.asciiHost, uri5.asciiHost);
} finally {
for each (var pref in prefData) {
for (var pref of prefData) {
if (prefs.prefHasUserValue(pref.name))
prefs.clearUserPref(pref.name);
}
+44
View File
@@ -0,0 +1,44 @@
function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
// check if hostname is unescaped before applying IDNA
var newURI = ios.newURI("http://\u5341%2ecom/", null, null);
do_check_eq(newURI.asciiHost, "xn--kkr.com");
// escaped UTF8
newURI.spec = "http://%e5%8d%81.com";
do_check_eq(newURI.asciiHost, "xn--kkr.com");
// There should be only allowed characters in hostname after
// unescaping and attempting to apply IDNA. "\x80" is illegal in
// UTF-8, so IDNA fails, and 0x80 is illegal in DNS too.
Assert.throws(() => { newURI.spec = "http://%80.com"; }, "illegal UTF character");
// test parsing URL with all possible host terminators
newURI.spec = "http://example.com?foo";
do_check_eq(newURI.asciiHost, "example.com");
newURI.spec = "http://example.com#foo";
do_check_eq(newURI.asciiHost, "example.com");
newURI.spec = "http://example.com:80";
do_check_eq(newURI.asciiHost, "example.com");
newURI.spec = "http://example.com/foo";
do_check_eq(newURI.asciiHost, "example.com");
// Characters that are invalid in the host, shouldn't be decoded.
newURI.spec = "http://example.com%3ffoo";
do_check_eq(newURI.asciiHost, "example.com%3ffoo");
newURI.spec = "http://example.com%23foo";
do_check_eq(newURI.asciiHost, "example.com%23foo");
newURI.spec = "http://example.com%3bfoo";
do_check_eq(newURI.asciiHost, "example.com%3bfoo");
newURI.spec = "http://example.com%3a80";
do_check_eq(newURI.asciiHost, "example.com%3a80");
newURI.spec = "http://example.com%2ffoo";
do_check_eq(newURI.asciiHost, "example.com%2ffoo");
newURI.spec = "http://example.com%00";
do_check_eq(newURI.asciiHost, "example.com%00");
}
@@ -0,0 +1,16 @@
const GOOD_COOKIE = "GoodCookie=OMNOMNOM";
function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var cookieURI = ios.newURI("http://mozilla.org/test_cookie_blacklist.js",
null, null);
var cookieService = Cc["@mozilla.org/cookieService;1"]
.getService(Ci.nsICookieService);
cookieService.setCookieStringFromHttp(cookieURI, cookieURI, null, "BadCookie1=\x01", null, null);
cookieService.setCookieStringFromHttp(cookieURI, cookieURI, null, "BadCookie2=\v", null, null);
cookieService.setCookieStringFromHttp(cookieURI, cookieURI, null, GOOD_COOKIE, null, null);
var storedCookie = cookieService.getCookieString(cookieURI, null);
do_check_eq(storedCookie, GOOD_COOKIE);
}
@@ -146,7 +146,7 @@ function test_binary_portion(start, length) {
test_seek_then_read,
];
for each(test in streamTests) {
for (var test of streamTests) {
let fileStream = new_file_input_stream(subFile);
let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
start, length);
@@ -207,7 +207,7 @@ function test_seek(dummy, partialFileStream, size) {
partialFileStream.QueryInterface(Ci.nsISeekableStream);
tests = [
var tests = [
[SET, 0],
[SET, 5],
[SET, 1000],
@@ -259,7 +259,7 @@ function test_seek(dummy, partialFileStream, size) {
];
let pos = 0;
for each(test in tests) {
for (var test of tests) {
let didThrow = false;
try {
partialFileStream.seek(test[0], test[1]);
@@ -298,7 +298,7 @@ function test_seek_then_read(fileStreamA, fileStreamB, size) {
let read = {};
tests = [
var tests = [
[SET, 0],
[read, 1000],
[read, 1000],
@@ -324,7 +324,7 @@ function test_seek_then_read(fileStreamA, fileStreamB, size) {
[read, 100],
];
for each(test in tests) {
for (var test of tests) {
if (test[0] === read) {
let didThrowA = false;
@@ -364,7 +364,7 @@ function test_text_portion(start, length) {
test_seek_then_readline,
];
for each(test in streamTests) {
for (var test of streamTests) {
let fileStream = new_file_input_stream(subFile)
.QueryInterface(Ci.nsILineInputStream);
let partialStream = new_partial_file_input_stream(do_get_file(binary_test_file_name),
@@ -400,7 +400,7 @@ function test_seek_then_readline(fileStreamA, fileStreamB, size) {
let read = {};
tests = [
var tests = [
[SET, 0],
[read, 5],
[read, 5],
@@ -430,7 +430,7 @@ function test_seek_then_readline(fileStreamA, fileStreamB, size) {
[read, 1],
];
for each(test in tests) {
for (var test of tests) {
if (test[0] === read) {
for (let i = 0; i < test[1]; ++i) {
+1 -1
View File
@@ -30,6 +30,6 @@ function check_file(file) {
}
function run_test() {
for each(let file in ["ua.css"])
for (let file of ["ua.css"])
check_file(file)
}
@@ -0,0 +1,181 @@
// This test is to verify Bug 1214079: when we failed to load a signed packaged
// content due to the bad signature, we are able to load in the next time since
// the cache is not cleaned up after signature verification.
//
// In order to verify it, we do two identical requests in a row, where the
// second request will be loaded from cache. The request is made for a signed
// package with bad signature. If the package cache isn't doomed after the
// first load, the second request will get valid data from the cache.
Cu.import('resource://gre/modules/LoadContextInfo.jsm');
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
var gPrefs = Cc["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var badSignature = [
"manifest-signature: AAAAAAAAAAAAAAAAAAAAA\r",
"--7B0MKBI3UH\r",
"Content-Location: manifest.webapp\r",
"Content-Type: application/x-web-app-manifest+json\r",
"\r",
"{",
" \"name\": \"My App\",",
" \"moz-resources\": [",
" {",
" \"src\": \"page2.html\",",
" \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"",
" },",
" {",
" \"src\": \"index.html\",",
" \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"",
" },",
" {",
" \"src\": \"scripts/script.js\",",
" \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"",
" },",
" {",
" \"src\": \"scripts/library.js\",",
" \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"",
" }",
" ],",
" \"moz-permissions\": [",
" {",
" \"systemXHR\": {",
" \"description\": \"Needed to download stuff\"",
" },",
" \"devicestorage:pictures\": {",
" \"description\": \"Need to load pictures\"",
" }",
" }",
" ],",
" \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",",
" \"moz-package-location\": \"https://example.com/myapp/app.pak\",",
" \"description\": \"A great app!\"",
"}\r",
"--7B0MKBI3UH\r",
"Content-Location: page2.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" page2.html",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: index.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" Last updated: 2015/10/01 14:10 PST",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/script.js\r",
"Content-Type: text/javascript\r",
"\r",
"// script.js",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/library.js\r",
"Content-Type: text/javascript\r",
"\r",
"// library.js",
"\r",
"--7B0MKBI3UH--"
].join("\n");
XPCOMUtils.defineLazyGetter(this, "uri", function() {
return "http://localhost:" + httpserver.identity.primaryPort;
});
// The active http server initialized in run_test
var httpserver = null;
// The packaged app service initialized in run_test
var paservice = null;
function run_test()
{
// setup test
httpserver = new HttpServer();
httpserver.registerPathHandler("/badSignature", badSignatureHandler);
httpserver.start(-1);
do_register_cleanup(function() {
gPrefs.clearUserPref("network.http.signed-packages.enabled");
});
paservice = Cc["@mozilla.org/network/packaged-app-service;1"]
.getService(Ci.nsIPackagedAppService);
ok(!!paservice, "test service exists");
gPrefs.setBoolPref("network.http.signed-packages.enabled", true);
add_test(test_badSignature_package);
add_test(test_badSignature_package);
// run tests
run_next_test();
}
//-----------------------------------------------------------------------------
// The number of times this package has been requested
// This number might be reset by tests that use it
var packagedAppRequestsMade = 0;
function badSignatureHandler(metadata, response)
{
packagedAppRequestsMade++;
if (packagedAppRequestsMade == 2) {
// The second request returns a 304 not modified response
response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
response.bodyOutputStream.write("", 0);
return;
}
response.setHeader("Content-Type", 'application/package');
var body = badSignature;
response.bodyOutputStream.write(body, body.length);
}
function getChannelForURL(url) {
let uri = createURI(url);
let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let principal = ssm.createCodebasePrincipal(uri, {});
let tmpChannel =
NetUtil.newChannel({
uri: url,
loadingPrincipal: principal,
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
});
tmpChannel.notificationCallbacks =
new LoadContextCallback(principal.appId,
principal.isInBrowserElement,
false,
false);
return tmpChannel;
}
function test_badSignature_package()
{
let packagePath = "/badSignature";
let url = uri + packagePath + "!//index.html";
let channel = getChannelForURL(url);
paservice.getResource(channel, {
onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
onCacheEntryAvailable: function (entry, isnew, appcache, status) {
// XXX: it returns NS_ERROR_FAILURE for a missing package
// and NS_ERROR_FILE_NOT_FOUND for a missing file from the package.
// Maybe make them both return NS_ERROR_FILE_NOT_FOUND?
notEqual(status, Cr.NS_OK, "NOT FOUND");
ok(!entry, "There should be no entry");
run_next_test();
}
});
}
+112 -20
View File
@@ -51,7 +51,7 @@ Listener.prototype = {
do_check_eq(this.available, count);
// Need to consume stream to avoid assertion
var str = new nsIBinaryInputStream(stream).readBytes(count);
equal(str, "<html>\r\n <head>\r\n <script src=\"/scripts/app.js\"></script>\r\n ...\r\n </head>\r\n ...\r\n</html>\r\n", "check proper content");
equal(str, "<html>\n Last updated: 2015/10/01 14:10 PST\n</html>\n", "check proper content");
}
catch (ex) {
do_throw(ex);
@@ -74,7 +74,7 @@ Listener.prototype = {
var testData = {
packageHeader: "manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n",
content: [
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n <head>\r\n <script src=\"/scripts/app.js\"></script>\r\n ...\r\n </head>\r\n ...\r\n</html>\r\n", type: "text/html" },
{ headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\n Last updated: 2015/10/01 14:10 PST\n</html>\n", type: "text/html" },
{ headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
{ headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
],
@@ -95,6 +95,79 @@ var testData = {
}
}
var badSignature = "manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n";
var goodSignature = "manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r\n";
var packageContent = [
"--7B0MKBI3UH\r",
"Content-Location: manifest.webapp\r",
"Content-Type: application/x-web-app-manifest+json\r",
"\r",
"{",
" \"name\": \"My App\",",
" \"moz-resources\": [",
" {",
" \"src\": \"page2.html\",",
" \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"",
" },",
" {",
" \"src\": \"index.html\",",
" \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"",
" },",
" {",
" \"src\": \"scripts/script.js\",",
" \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"",
" },",
" {",
" \"src\": \"scripts/library.js\",",
" \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"",
" }",
" ],",
" \"moz-permissions\": [",
" {",
" \"systemXHR\": {",
" \"description\": \"Needed to download stuff\"",
" },",
" \"devicestorage:pictures\": {",
" \"description\": \"Need to load pictures\"",
" }",
" }",
" ],",
" \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",",
" \"moz-package-location\": \"https://example.com/myapp/app.pak\",",
" \"description\": \"A great app!\"",
"}\r",
"--7B0MKBI3UH\r",
"Content-Location: page2.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" page2.html",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: index.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" Last updated: 2015/10/01 14:10 PST",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/script.js\r",
"Content-Type: text/javascript\r",
"\r",
"// script.js",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/library.js\r",
"Content-Type: text/javascript\r",
"\r",
"// library.js",
"\r",
"--7B0MKBI3UH--"
].join("\n");
function contentHandler(metadata, response)
{
response.setHeader("Content-Type", 'application/package');
@@ -108,16 +181,23 @@ function regularContentHandler(metadata, response)
response.bodyOutputStream.write(body, body.length);
}
function contentHandlerWithSignature(metadata, response)
function contentHandlerWithBadSignature(metadata, response)
{
response.setHeader("Content-Type", 'application/package');
var body = testData.packageHeader + testData.getData();
var body = badSignature + packageContent;
response.bodyOutputStream.write(body, body.length);
}
function contentHandlerWithGoodSignature(metadata, response)
{
response.setHeader("Content-Type", 'application/package');
var body = goodSignature + packageContent;
response.bodyOutputStream.write(body, body.length);
}
var httpserver = null;
var originalPref = false;
var originalDevMode = false;
var originalSignedAppEnabled = false;
function run_test()
{
@@ -125,46 +205,58 @@ function run_test()
httpserver = new HttpServer();
httpserver.registerPathHandler("/package", contentHandler);
httpserver.registerPathHandler("/regular", regularContentHandler);
httpserver.registerPathHandler("/package_with_signature", contentHandlerWithSignature);
httpserver.registerPathHandler("/package_with_good_signature", contentHandlerWithGoodSignature);
httpserver.registerPathHandler("/package_with_bad_signature", contentHandlerWithBadSignature);
httpserver.start(-1);
// Enable the feature and save the original pref value
originalPref = Services.prefs.getBoolPref("network.http.enable-packaged-apps");
originalDevMode = Services.prefs.getBoolPref("network.http.packaged-apps-developer-mode");
originalSignedAppEnabled = Services.prefs.getBoolPref("network.http.signed-packages.enabled");
Services.prefs.setBoolPref("network.http.enable-packaged-apps", true);
Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", false);
Services.prefs.setBoolPref("network.http.signed-packages.enabled", true);
do_register_cleanup(reset_pref);
add_test(test_channel);
add_test(test_channel_no_notificationCallbacks);
add_test(test_channel_uris);
add_test(test_channel_with_signature);
add_test(test_channel_with_signature_dev_mode);
add_test(test_channel_with_bad_signature_from_trusted_origin);
add_test(test_channel_with_bad_signature);
add_test(test_channel_with_good_signature);
// run tests
run_next_test();
}
function test_channel_with_signature() {
var channel = make_channel(uri+"/package_with_signature!//index.html");
function test_channel_with_bad_signature() {
var channel = make_channel(uri+"/package_with_bad_signature!//index.html");
channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false);
channel.asyncOpen(new Listener(function(l) {
// Since the manifest verification is not implemented yet, we should
// get NS_ERROR_FILE_NOT_FOUND if the package has a signature while
// not in developer mode.
do_check_true(l.gotFileNotFound);
run_next_test();
}), null);
}
function test_channel_with_signature_dev_mode() {
Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", true);
var channel = make_channel(uri+"/package_with_signature!//index.html");
function test_channel_with_bad_signature_from_trusted_origin() {
let pref = "network.http.signed-packages.trusted-origin";
ok(!!Ci.nsISupportsString, "Ci.nsISupportsString");
let origin = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
origin.data = uri;
Services.prefs.setComplexValue(pref, Ci.nsISupportsString, origin);
var channel = make_channel(uri+"/package_with_bad_signature!//index.html");
channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false);
channel.asyncOpen(new Listener(function(l) {
do_check_true(l.gotStopRequestOK);
Services.prefs.clearUserPref(pref);
run_next_test();
}), null);
}
function test_channel_with_good_signature() {
var channel = make_channel(uri+"/package_with_good_signature!//index.html");
channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false);
channel.asyncOpen(new Listener(function(l) {
do_check_true(l.gotStopRequestOK);
Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", false);
run_next_test();
}), null);
}
@@ -205,5 +297,5 @@ function check_regular_response(request, buffer) {
function reset_pref() {
// Set the pref to its original value
Services.prefs.setBoolPref("network.http.enable-packaged-apps", originalPref);
Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", originalDevMode);
Services.prefs.setBoolPref("network.http.signed-packages.enabled", originalSignedAppEnabled);
}
+81 -9
View File
@@ -113,6 +113,77 @@ var testData = {
}
}
var signedPackage = [
"manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r",
"--7B0MKBI3UH\r",
"Content-Location: manifest.webapp\r",
"Content-Type: application/x-web-app-manifest+json\r",
"\r",
"{",
" \"name\": \"My App\",",
" \"moz-resources\": [",
" {",
" \"src\": \"page2.html\",",
" \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"",
" },",
" {",
" \"src\": \"index.html\",",
" \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"",
" },",
" {",
" \"src\": \"scripts/script.js\",",
" \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"",
" },",
" {",
" \"src\": \"scripts/library.js\",",
" \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"",
" }",
" ],",
" \"moz-permissions\": [",
" {",
" \"systemXHR\": {",
" \"description\": \"Needed to download stuff\"",
" },",
" \"devicestorage:pictures\": {",
" \"description\": \"Need to load pictures\"",
" }",
" }",
" ],",
" \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",",
" \"moz-package-location\": \"https://example.com/myapp/app.pak\",",
" \"description\": \"A great app!\"",
"}\r",
"--7B0MKBI3UH\r",
"Content-Location: page2.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" page2.html",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: index.html\r",
"Content-Type: text/html\r",
"\r",
"<html>",
" Last updated: 2015/10/01 14:10 PST",
"</html>",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/script.js\r",
"Content-Type: text/javascript\r",
"\r",
"// script.js",
"\r",
"--7B0MKBI3UH\r",
"Content-Location: scripts/library.js\r",
"Content-Type: text/javascript\r",
"\r",
"// library.js",
"\r",
"--7B0MKBI3UH--"
].join("\n");
XPCOMUtils.defineLazyGetter(this, "uri", function() {
return "http://localhost:" + httpserver.identity.primaryPort;
});
@@ -142,18 +213,16 @@ function run_test()
httpserver.registerPathHandler("/signedPackage", signedPackagedAppContentHandler);
httpserver.start(-1);
// We will enable the developer mode in 'test_signed_package_callback'.
// So restore it after testing.
//
// TODO: To be removed in Bug 1178518.
do_register_cleanup(function() {
gPrefs.clearUserPref("network.http.packaged-apps-developer-mode");
gPrefs.clearUserPref("network.http.signed-packages.enabled");
});
paservice = Cc["@mozilla.org/network/packaged-app-service;1"]
.getService(Ci.nsIPackagedAppService);
ok(!!paservice, "test service exists");
gPrefs.setBoolPref("network.http.signed-packages.enabled", true);
add_test(test_bad_args);
add_test(test_callback_gets_called);
@@ -495,7 +564,7 @@ function test_worse_package_5() {
function signedPackagedAppContentHandler(metadata, response)
{
response.setHeader("Content-Type", 'application/package');
var body = testData.packageHeader + testData.getData();
var body = signedPackage;
response.bodyOutputStream.write(body, body.length);
}
@@ -513,9 +582,6 @@ let dummyCacheListener = {
function test_signed_package_callback()
{
// TODO: To be removed in Bug 1178518.
gPrefs.setBoolPref("network.http.packaged-apps-developer-mode", true);
packagePath = "/signedPackage";
let url = uri + packagePath + "!//index.html";
let channel = getChannelForURL(url, {
@@ -534,6 +600,9 @@ function test_signed_package_callback()
iid.equals(Ci.nsIPackagedAppChannelListener)) {
return this;
}
if (iid.equals(Ci.nsILoadContext)) {
return new LoadContextCallback(1024, false, false, false);
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
});
@@ -560,6 +629,9 @@ function test_unsigned_package_callback()
iid.equals(Ci.nsIPackagedAppChannelListener)) {
return this;
}
if (iid.equals(Ci.nsILoadContext)) {
return new LoadContextCallback(1024, false, false, false);
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
});
+1 -1
View File
@@ -98,7 +98,7 @@ function test_verify_manifest(aHeader, aManifest, aShouldSucceed) {
run_next_test();
}
};
packagedAppUtils.verifyManifest(aHeader, aManifest, fakeVerifier);
packagedAppUtils.verifyManifest(aHeader, aManifest, fakeVerifier, false);
}
}
+59 -53
View File
@@ -38,19 +38,10 @@ let gLoadContextInfoFactory =
const kUriIdx = 0;
const kStatusCodeIdx = 1;
const kVerificationSuccessIdx = 2;
function enable_developer_mode()
{
gPrefs.setBoolPref("network.http.packaged-apps-developer-mode", true);
}
function reset_developer_mode()
{
gPrefs.clearUserPref("network.http.packaged-apps-developer-mode");
}
const kContentIdx = 3;
function createVerifierListener(aExpecetedCallbacks,
aExpectedOrigin,
aExpectedPackageId,
aExpectedIsSigned,
aPackageCacheEntry) {
let cnt = 0;
@@ -77,33 +68,47 @@ function createVerifierListener(aExpecetedCallbacks,
if (isManifest) {
// Check if the verifier got the right package info.
equal(gVerifier.packageOrigin, aExpectedOrigin, 'package origin');
equal(gVerifier.packageIdentifier, aExpectedPackageId, 'package identifier');
equal(gVerifier.isPackageSigned, aExpectedIsSigned, 'is package signed');
// Check if the verifier wrote the signed package origin to the cache.
ok(!!aPackageCacheEntry, aPackageCacheEntry.key);
let signePakOriginInCache = aPackageCacheEntry.getMetaDataElement('signed-pak-origin');
equal(signePakOriginInCache,
(aExpectedIsSigned ? aExpectedOrigin : ''),
'signed-pak-origin in cache');
let signePakIdInCache = aPackageCacheEntry.getMetaDataElement('package-id');
equal(signePakIdInCache,
(aExpectedIsSigned ? aExpectedPackageId : ''),
'package-id in cache');
}
if (isLastPart) {
reset_developer_mode();
run_next_test();
}
},
};
};
function feedResources(aExpectedCallbacks) {
function feedData(aString) {
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stringStream.setData(aString, aString.length);
gVerifier.onDataAvailable(null, null, stringStream, 0, aString.length);
}
function feedResources(aExpectedCallbacks, aSignature) {
for (let i = 0; i < aExpectedCallbacks.length; i++) {
let expectedCallback = aExpectedCallbacks[i];
let isLastPart = (i === aExpectedCallbacks.length - 1);
// Start request.
let uri = gIoService.newURI(expectedCallback[kUriIdx], null, null);
gVerifier.onStartRequest(null, uri);
// Feed data at once.
let contentString = expectedCallback[kContentIdx];
if (contentString !== undefined) {
feedData(contentString);
}
// Stop request.
let info = gVerifier.createResourceCacheInfo(uri,
null,
expectedCallback[kStatusCodeIdx],
@@ -121,12 +126,12 @@ function createPackageCache(aPackageUriAsAscii, aLoadContextInfo) {
return cacheStorage.openTruncate(uri, '');
}
function test_no_signature(aDeveloperMode) {
function test_no_signature(aBypassVerification) {
const kOrigin = 'http://foo.com';
aDeveloperMode = !!aDeveloperMode;
aBypassVerification = !!aBypassVerification;
// If the package has no signature and not in developer mode, the package is unsigned
// If the package has no signature, the package is unsigned
// but the verification result is always true.
const expectedCallbacks = [
@@ -142,79 +147,80 @@ function test_no_signature(aDeveloperMode) {
let isPackageSigned = false;
// We only require the package URL to be different in each test case.
let packageUriString = kOrigin + '/pak' + (aDeveloperMode ? '-dev' : '');
let packageUriString = kOrigin + '/pak' + (aBypassVerification ? '-dev' : '');
let packageCacheEntry =
createPackageCache(packageUriString, gLoadContextInfoFactory.default);
let verifierListener = createVerifierListener(expectedCallbacks,
kOrigin,
'',
isPackageSigned,
packageCacheEntry);
gVerifier.init(verifierListener, kOrigin, '', packageCacheEntry);
feedResources(expectedCallbacks);
feedResources(expectedCallbacks, '');
}
function test_invalid_signature(aDeveloperMode) {
function test_invalid_signature(aBypassVerification) {
const kOrigin = 'http://bar.com';
aDeveloperMode = !!aDeveloperMode;
aBypassVerification = !!aBypassVerification;
// Since we haven't implemented signature verification, the verification always
// fails if the signature exists.
let verificationResult = aDeveloperMode; // Verification always success in developer mode.
let isPackageSigned = aDeveloperMode; // Package is always considered as signed in developer mode.
let verificationResult = aBypassVerification; // Verification always success in developer mode.
let isPackageSigned = aBypassVerification; // Package is always considered as signed in developer mode.
const kPackagedId = '611FC2FE-491D-4A47-B3B3-43FBDF6F404F';
const kManifestContent = 'Content-Location: manifest.webapp\r\n' +
'Content-Type: application/x-web-app-manifest+json\r\n' +
'\r\n' +
'{ "package-identifier": "' + kPackagedId + '" }';
const expectedCallbacks = [
// URL statusCode verificationResult
[kOrigin + '/manifest', Cr.NS_OK, verificationResult],
[kOrigin + '/1.html', Cr.NS_OK, verificationResult],
[kOrigin + '/2.js', Cr.NS_OK, verificationResult],
[kOrigin + '/3.jpg', Cr.NS_OK, verificationResult],
[kOrigin + '/4.html', Cr.NS_OK, verificationResult],
[kOrigin + '/5.css', Cr.NS_OK, verificationResult],
// URL statusCode verificationResult content
[kOrigin + '/manifest', Cr.NS_OK, verificationResult, kManifestContent],
[kOrigin + '/1.html', Cr.NS_OK, verificationResult, 'abc'],
[kOrigin + '/2.js', Cr.NS_OK, verificationResult, 'abc'],
[kOrigin + '/3.jpg', Cr.NS_OK, verificationResult, 'abc'],
[kOrigin + '/4.html', Cr.NS_OK, verificationResult, 'abc'],
[kOrigin + '/5.css', Cr.NS_OK, verificationResult, 'abc'],
];
let packageUriString = kOrigin + '/pak' + (aDeveloperMode ? '-dev' : '');
let packageUriString = kOrigin + '/pak' + (aBypassVerification ? '-dev' : '');
let packageCacheEntry =
createPackageCache(packageUriString, gLoadContextInfoFactory.private);
let verifierListener = createVerifierListener(expectedCallbacks,
kOrigin,
aBypassVerification ? kPackagedId : '',
isPackageSigned,
packageCacheEntry);
gVerifier.init(verifierListener, kOrigin, 'invalid signature', packageCacheEntry);
let signature = 'manifest-signature: 11111111111111111111111';
gVerifier.init(verifierListener, kOrigin, signature, packageCacheEntry);
feedResources(expectedCallbacks);
feedResources(expectedCallbacks, signature);
}
function test_no_signature_developer_mode()
{
enable_developer_mode()
test_no_signature(true);
}
function test_invalid_signature_developer_mode()
{
enable_developer_mode()
function test_invalid_signature_bypass_verification() {
let pref = "network.http.signed-packages.trusted-origin";
ok(!!Ci.nsISupportsString, "Ci.nsISupportsString");
let origin = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
origin.data = "http://bar.com";
gPrefs.setComplexValue(pref, Ci.nsISupportsString, origin);
test_invalid_signature(true);
gPrefs.clearUserPref(pref);
}
function run_test()
{
ok(!!gVerifier);
// Test cases in non-developer mode.
add_test(test_no_signature);
add_test(test_invalid_signature);
// Test cases in developer mode.
add_test(test_no_signature_developer_mode);
add_test(test_invalid_signature_developer_mode);
add_test(test_invalid_signature_bypass_verification);
// run tests
run_next_test();
+2 -2
View File
@@ -34,13 +34,13 @@ function err(file, lineNo, msg) {
function run_test()
{
for each (var test in test_array) {
for (var test of test_array) {
var lineStream = new_line_input_stream(test.file);
var lineNo = 0;
var more = false;
var line = {};
more = lineStream.readLine(line);
for each (var check in test.lines) {
for (var check of test.lines) {
++lineNo;
if (lineNo == test.lines.length) {
if (more) err(test.file, lineNo, "There should be no more data after the last line");
+2 -2
View File
@@ -428,7 +428,7 @@ SocksTestServer.prototype = {
var argv = [];
// marshaled: socks_ver|server_port|dest_host|dest_port|<remote|local>
for each (var test in this.test_cases) {
for (var test of this.test_cases) {
var arg = test.type + '|' +
String(socks_listen_port) + '|' +
test.host + '|' + test.port + '|';
@@ -467,7 +467,7 @@ SocksTestServer.prototype = {
}
this.client_subprocess = null;
}
for each (var client in this.client_connections)
for (var client of this.client_connections)
client.close();
this.client_connections = [];
if (this.listener) {
+37 -5
View File
@@ -50,7 +50,7 @@ function test_setEmptyPath()
["http://example.com:80/a", "http://example.com/tests/dom/tests"],
].map(pairToURLs);
for each (var [provided, target] in pairs)
for (var [provided, target] of pairs)
{
symmetricEquality(false, target, provided);
@@ -77,7 +77,7 @@ function test_setQuery()
["http://example.com/?f", "http://example.com/?foo"],
].map(pairToURLs);
for each (var [provided, target] in pairs) {
for (var [provided, target] of pairs) {
symmetricEquality(false, provided, target);
provided.query = "foo";
@@ -135,7 +135,7 @@ function test_setRef()
["http://example.com:80/a", "xxxxxxxxxxxxxx", "http://example.com:80/a#xxxxxxxxxxxxxx"],
];
for each (var [before, ref, result] in tests)
for (var [before, ref, result] of tests)
{
/* Test1: starting with empty ref */
var a = stringToURL(before);
@@ -220,8 +220,9 @@ function test_clearedSpec()
symmetricEquality(true, url, ref);
}
function test_escapeQueryBrackets()
function test_escapeBrackets()
{
// Query
var url = stringToURL("http://example.com/?a[x]=1");
do_check_eq(url.spec, "http://example.com/?a[x]=1");
@@ -233,6 +234,14 @@ function test_escapeQueryBrackets()
url = stringToURL("http://[2001::1]/?a%5Bx%5D=1");
do_check_eq(url.spec, "http://[2001::1]/?a%5Bx%5D=1");
// Path
url = stringToURL("http://example.com/brackets[x]/test");
do_check_eq(url.spec, "http://example.com/brackets[x]/test");
url = stringToURL("http://example.com/a%5Bx%5D/test");
do_check_eq(url.spec, "http://example.com/a%5Bx%5D/test");
}
function test_apostropheEncoding()
@@ -243,6 +252,27 @@ function test_apostropheEncoding()
do_check_eq(url.spec, "http://example.com/dir'/file'.ext'");
}
function test_accentEncoding()
{
var url = stringToURL("http://example.com/?hello=`");
do_check_eq(url.spec, "http://example.com/?hello=`");
do_check_eq(url.query, "hello=`");
url = stringToURL("http://example.com/?hello=%2C");
do_check_eq(url.spec, "http://example.com/?hello=%2C");
do_check_eq(url.query, "hello=%2C");
}
function test_percentDecoding()
{
var url = stringToURL("http://%70%61%73%74%65%62%69%6E.com");
do_check_eq(url.spec, "http://pastebin.com/");
// We shouldn't unescape characters that are not allowed in the hostname.
url = stringToURL("http://example.com%0a%23.google.com/");
do_check_eq(url.spec, "http://example.com%0a%23.google.com/");
}
function run_test()
{
test_setEmptyPath();
@@ -251,6 +281,8 @@ function run_test()
test_ipv6();
test_ipv6_fail();
test_clearedSpec();
test_escapeQueryBrackets();
test_escapeBrackets();
test_apostropheEncoding();
test_accentEncoding();
test_percentDecoding();
}
+4
View File
@@ -340,3 +340,7 @@ firefox-appdir = browser
[test_dns_disable_ipv6.js]
[test_packaged_app_service_paths.js]
[test_bug1195415.js]
[test_cookie_blacklist.js]
[test_packaged_app_bug1214079.js]
[test_bug412457.js]
@@ -207,6 +207,7 @@ class FasterMakeBackend(CommonBackend):
)
pp.out = JarManifestParser()
pp.do_include(obj.path)
self.backend_input_files |= pp.includes
for jarinfo in pp.out:
install_target = obj.install_target
@@ -301,6 +302,7 @@ class FasterMakeBackend(CommonBackend):
mk.create_rule(['default'])
mk.add_statement('TOPSRCDIR = %s' % self.environment.topsrcdir)
mk.add_statement('TOPOBJDIR = %s' % self.environment.topobjdir)
mk.add_statement('BACKEND = %s' % self._backend_output_list_file)
# Add a few necessary variables inherited from configure
for var in (
@@ -331,6 +333,10 @@ class FasterMakeBackend(CommonBackend):
mk.create_rule([target]).add_dependencies(
'$(TOPOBJDIR)/%s' % d for d in deps)
# Add backend dependencies:
mk.create_rule([self._backend_output_list_file]).add_dependencies(
self.backend_input_files)
mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk')
for base, install_manifest in self._install_manifests.iteritems():
+59
View File
@@ -8,7 +8,13 @@
#include "certdb.h"
#include "pkix/pkixnss.h"
#include "mozilla/ArrayUtils.h"
#include "MainThreadUtils.h"
#include "mozilla/Preferences.h"
#include "nsComponentManagerUtils.h"
#include "nsIFile.h"
#include "nsIFileStreams.h"
#include "nsIX509CertDB.h"
#include "nsNetUtil.h"
#include "nsNSSCertificate.h"
#include "prerror.h"
#include "secerr.h"
@@ -34,9 +40,15 @@ using namespace mozilla::pkix;
extern PRLogModuleInfo* gPIPNSSLog;
static const unsigned int DEFAULT_MIN_RSA_BITS = 2048;
static char kDevImportedDER[] =
"network.http.signed-packages.developer-root";
namespace mozilla { namespace psm {
StaticMutex AppTrustDomain::sMutex;
nsAutoArrayPtr<unsigned char> AppTrustDomain::sDevImportedDERData(nullptr);
unsigned int AppTrustDomain::sDevImportedDERLen = 0;
AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg)
: mCertChain(certChain)
, mPinArg(pinArg)
@@ -101,6 +113,53 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot);
break;
case nsIX509CertDB::DeveloperImportedRoot: {
StaticMutexAutoLock lock(sMutex);
if (!sDevImportedDERData) {
MOZ_ASSERT(!NS_IsMainThread());
nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
if (!file) {
PR_SetError(SEC_ERROR_IO, 0);
return SECFailure;
}
nsresult rv = file->InitWithNativePath(
Preferences::GetCString(kDevImportedDER));
if (NS_FAILED(rv)) {
PR_SetError(SEC_ERROR_IO, 0);
return SECFailure;
}
nsCOMPtr<nsIInputStream> inputStream;
NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, -1,
nsIFileInputStream::CLOSE_ON_EOF);
if (!inputStream) {
PR_SetError(SEC_ERROR_IO, 0);
return SECFailure;
}
uint64_t length;
rv = inputStream->Available(&length);
if (NS_FAILED(rv)) {
PR_SetError(SEC_ERROR_IO, 0);
return SECFailure;
}
char* data = new char[length];
rv = inputStream->Read(data, length, &sDevImportedDERLen);
if (NS_FAILED(rv)) {
PR_SetError(SEC_ERROR_IO, 0);
return SECFailure;
}
MOZ_ASSERT(length == sDevImportedDERLen);
sDevImportedDERData = reinterpret_cast<unsigned char*>(data);
}
trustedDER.data = sDevImportedDERData;
trustedDER.len = sDevImportedDERLen;
break;
}
default:
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;
+6
View File
@@ -8,6 +8,8 @@
#define mozilla_psm_AppsTrustDomain_h
#include "pkix/pkixtypes.h"
#include "mozilla/StaticMutex.h"
#include "nsAutoPtr.h"
#include "nsDebug.h"
#include "nsIX509CertDB.h"
#include "ScopedNSSTypes.h"
@@ -69,6 +71,10 @@ private:
void* mPinArg; // non-owning!
ScopedCERTCertificate mTrustedRoot;
unsigned int mMinRSABits;
static StaticMutex sMutex;
static nsAutoArrayPtr<unsigned char> sDevImportedDERData;
static unsigned int sDevImportedDERLen;
};
} } // namespace mozilla::psm
+9 -1
View File
@@ -46,7 +46,7 @@ interface nsIVerifySignedManifestCallback : nsISupports
* This represents a service to access and manipulate
* X.509 certificates stored in a database.
*/
[scriptable, uuid(0a47571d-602c-4b21-9f52-c3d0e681d83a)]
[scriptable, uuid(a36c45fb-f7b5-423e-a0f7-ea1eb4fd60b5)]
interface nsIX509CertDB : nsISupports {
/**
@@ -319,6 +319,14 @@ interface nsIX509CertDB : nsISupports {
const AppTrustedRoot AddonsPublicRoot = 7;
const AppTrustedRoot AddonsStageRoot = 8;
const AppTrustedRoot PrivilegedPackageRoot = 9;
/*
* If DeveloperImportedRoot is set as trusted root, a CA from local file
* system will be imported. Only used when preference
* "network.http.packaged-apps-developer-mode" is set.
* The path of the CA is specified by preference
* "network.http.packaged-apps-developer-trusted-root".
*/
const AppTrustedRoot DeveloperImportedRoot = 10;
void openSignedAppFileAsync(in AppTrustedRoot trustedRoot,
in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback);
@@ -13,7 +13,7 @@
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
prefs.setIntPref("network.auth.allow-subresource-auth", 2);
prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
// Class monitoring number of open dialog windows
// It checks there is always open just a single dialog per application
function dialogMonitor() {
@@ -7223,6 +7223,14 @@
"n_values": 10,
"description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS"
},
"COOKIE_SCHEME_SECURITY": {
"alert_emails": ["seceng@mozilla.org"],
"expires_in_version": "50",
"kind": "enumerated",
"n_values": 10,
"releaseChannelCollection": "opt-out",
"description": "How often are secure cookies set from non-secure origins, and vice-versa? 0=nonsecure/http, 1=nonsecure/https, 2=secure/http, 3=secure/https"
},
"NTLM_MODULE_USED_2": {
"expires_in_version": "never",
"kind": "enumerated",
@@ -10,7 +10,7 @@ function test() {
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
prefs.setIntPref("network.auth.allow-subresource-auth", 2);
prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
var pm = Services.perms;
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
@@ -52,11 +52,9 @@ NS_IMPL_ISUPPORTS(OfflineCacheUpdateParent,
// OfflineCacheUpdateParent <public>
//-----------------------------------------------------------------------------
// TODO: Bug 1191740 - Add OriginAttributes in TabContext
OfflineCacheUpdateParent::OfflineCacheUpdateParent(uint32_t aAppId,
bool aIsInBrowser)
OfflineCacheUpdateParent::OfflineCacheUpdateParent(const OriginAttributes& aAttrs)
: mIPCClosed(false)
, mOriginAttributes(aAppId, aIsInBrowser)
, mOriginAttributes(aAttrs)
{
// Make sure the service has been initialized
nsOfflineCacheUpdateService::EnsureService();
@@ -45,7 +45,7 @@ public:
mIPCClosed = true;
}
OfflineCacheUpdateParent(uint32_t aAppId, bool aIsInBrowser);
explicit OfflineCacheUpdateParent(const mozilla::OriginAttributes& aAttrs);
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
private:
+76
View File
@@ -0,0 +1,76 @@
/* 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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function CommandLineHandler() {}
CommandLineHandler.prototype = {
classID: Components.ID("{6d69c782-40a3-469b-8bfd-3ee366105a4a}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
handle: function handle(cmdLine) {
let args = Cc["@mozilla.org/hash-property-bag;1"].
createInstance(Ci.nsIWritablePropertyBag);
let inTestMode = this._handleTestMode(cmdLine, args);
if (inTestMode) {
// Open the mochitest shim window, which configures the runtime for tests.
Services.ww.openWindow(null,
"chrome://webapprt/content/mochitest.xul",
"_blank",
"chrome,dialog=no",
args);
} else {
// We're opening the window here in order to show it as soon as possible.
let window = Services.ww.openWindow(null,
"chrome://webapprt/content/webapp.xul",
"_blank",
"chrome,dialog=no,resizable,scrollbars,centerscreen",
null);
// Load the module to start up the app
Cu.import("resource://webapprt/modules/Startup.jsm");
startup(window).then(null, function (aError) {
dump("Error: " + aError + "\n");
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
});
}
},
_handleTestMode: function _handleTestMode(cmdLine, args) {
// -test-mode [url]
let idx = cmdLine.findFlag("test-mode", true);
if (idx < 0)
return false;
let url;
let urlIdx = idx + 1;
if (urlIdx < cmdLine.length) {
let potentialURL = cmdLine.getArgument(urlIdx);
if (potentialURL && potentialURL[0] != "-") {
try {
url = Services.io.newURI(potentialURL, null, null);
} catch (err) {
throw Components.Exception(
"-test-mode argument is not a valid URL: " + potentialURL,
Components.results.NS_ERROR_INVALID_ARG);
}
cmdLine.removeArguments(urlIdx, urlIdx);
args.setProperty("url", url.spec);
}
}
cmdLine.removeArguments(idx, idx);
return true;
},
helpInfo : "",
};
var components = [CommandLineHandler];
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+118
View File
@@ -0,0 +1,118 @@
/* 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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const UNKNOWN_FAIL = ["geolocation", "desktop-notification"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
function ContentPermission() {}
ContentPermission.prototype = {
classID: Components.ID("{07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
_getChromeWindow: function(aWindow) {
return aWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow);
},
prompt: function(request) {
// Only allow exactly one permission request here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Reuse any remembered permission preferences
let result =
Services.perms.testExactPermissionFromPrincipal(request.principal,
perm.type);
// We used to use the name "geo" for the geolocation permission, now we're
// using "geolocation". We need to check both to support existing
// installations.
if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
perm.type == "geolocation") {
let geoResult = Services.perms.testExactPermission(request.principal.URI,
"geo");
// We override the result only if the "geo" permission was allowed or
// denied.
if (geoResult == Ci.nsIPermissionManager.ALLOW_ACTION ||
geoResult == Ci.nsIPermissionManager.DENY_ACTION) {
result = geoResult;
}
}
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return;
} else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
(result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
request.cancel();
return;
}
// Display a prompt at the top level
let {name} = WebappRT.localeManifest;
let requestingWindow = request.window.top;
let chromeWin = this._getChromeWindow(requestingWindow);
let bundle = Services.strings.createBundle("chrome://webapprt/locale/webapp.properties");
// Construct a prompt with share/don't and remember checkbox
let remember = {value: false};
let choice = Services.prompt.confirmEx(
chromeWin,
bundle.formatStringFromName(perm.type + ".title", [name], 1),
bundle.GetStringFromName(perm.type + ".description"),
// Set both buttons to strings with the cancel button being default
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
bundle.GetStringFromName(perm.type + ".allow"),
bundle.GetStringFromName(perm.type + ".deny"),
null,
bundle.GetStringFromName(perm.type + ".remember"),
remember);
let action = Ci.nsIPermissionManager.ALLOW_ACTION;
if (choice != 0) {
action = Ci.nsIPermissionManager.DENY_ACTION;
}
if (remember.value) {
// Persist the choice if the user wants to remember
Services.perms.addFromPrincipal(request.principal, perm.type, action);
} else {
// Otherwise allow the permission for the current session
Services.perms.addFromPrincipal(request.principal, perm.type, action,
Ci.nsIPermissionManager.EXPIRE_SESSION);
}
// Trigger the selected choice
if (choice == 0) {
request.allow();
}
else {
request.cancel();
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermission]);
+56
View File
@@ -0,0 +1,56 @@
/* 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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const WEBAPP_REGISTRY_DIR = "WebappRegD";
const NS_APP_CHROME_DIR_LIST = "AChromDL";
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function DirectoryProvider() {}
DirectoryProvider.prototype = {
classID: Components.ID("{e1799fda-4b2f-4457-b671-e0641d95698d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
Ci.nsIDirectoryServiceProvider2]),
getFile: function(prop, persistent) {
if (prop == WEBAPP_REGISTRY_DIR) {
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
dir.initWithPath(WebappRT.config.registryDir);
return dir;
}
// We return null to show failure instead of throwing an error,
// which works with the way the interface is called (per bug 529077).
return null;
},
getFiles: function(prop, persistent) {
if (prop == NS_APP_CHROME_DIR_LIST) {
return {
_done: false,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
hasMoreElements: function() {
return !this._done;
},
getNext: function() {
this._done = true;
return FileUtils.getDir("AppRegD", ["chrome"], false);
}
};
}
return null;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DirectoryProvider]);
+35
View File
@@ -0,0 +1,35 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["DownloadView"];
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Downloads.jsm");
this.DownloadView = {
init: function() {
Downloads.getList(Downloads.ALL)
.then(list => list.addView(this))
.catch(Cu.reportError);
},
onDownloadAdded: function(aDownload) {
let dmWindow = Services.wm.getMostRecentWindow("Download:Manager");
if (dmWindow) {
dmWindow.focus();
} else {
Services.ww.openWindow(null,
"chrome://webapprt/content/downloads/downloads.xul",
"Download:Manager",
"chrome,dialog=no,resizable",
null);
}
},
};
DownloadView.init();
+16
View File
@@ -0,0 +1,16 @@
# 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 config.mk explicitly so we can override FINAL_TARGET.
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
libs:: $(call mkdir_deps,$(FINAL_TARGET))
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'resource webapprt ./')
MOZ_APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
DEFINES += -DMOZ_APP_BUILDID=$(MOZ_APP_BUILDID)
$(FINAL_TARGET)/webapprt.ini: $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt
+148
View File
@@ -0,0 +1,148 @@
/* 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/. */
"use strict";
const { interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
function paymentSuccess(aRequestId) {
return function(aResult) {
closePaymentWindow(aRequestId, function() {
cpmm.sendAsyncMessage("Payment:Success", { requestId: aRequestId,
result: aResult });
});
};
}
function paymentFailed(aRequestId) {
return function(aErrorMsg) {
closePaymentWindow(aRequestId, function() {
cpmm.sendAsyncMessage("Payment:Failed", { requestId: aRequestId,
errorMsg: aErrorMsg });
});
};
}
var payments = {};
function closePaymentWindow(aId, aCallback) {
if (payments[aId]) {
payments[aId].handled = true;
payments[aId].win.close();
payments[aId] = null;
}
aCallback();
}
function PaymentUI() {}
PaymentUI.prototype = {
classID: Components.ID("{ede1124f-72e8-4a31-9567-3270d46f21fb}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
confirmPaymentRequest: function(aRequestId, aRequests, aSuccessCb, aErrorCb) {
// If there's only one payment provider that will work, just move on
// without prompting the user.
if (aRequests.length == 1) {
aSuccessCb.onresult(aRequestId, aRequests[0].type);
return;
}
let items = [];
// Otherwise, let the user select a payment provider from a list.
for (let i = 0; i < aRequests.length; i++) {
let request = aRequests[i];
let requestText = request.providerName;
if (request.productPrice && Array.isArray(request.productPrice)) {
// We should guess the user currency and use that instead.
requestText += " (" + request.productPrice[0].amount + " " +
request.productPrice[0].currency + ")";
}
items.push(requestText);
}
let selected = {};
let bundle = Services.strings.
createBundle("chrome://webapprt/locale/webapp.properties");
let result = Services.prompt.
select(null, bundle.GetStringFromName("paymentDialog.title"),
bundle.GetStringFromName("paymentDialog.message"),
items.length, items, selected);
if (result) {
aSuccessCb.onresult(aRequestId,
aRequests[selected.value].type);
} else {
aErrorCb.onresult(aRequestId, "USER_CANCELLED");
}
},
showPaymentFlow: function(aRequestId, aPaymentFlowInfo, aErrorCb) {
let win = Services.ww.
openWindow(null,
"chrome://webapprt/content/webapp.xul",
"_blank",
"chrome,dialog=no,resizable,scrollbars,centerscreen",
null);
// Store a reference to the window so that we can close it when the payment
// succeeds or fails.
payments[aRequestId] = { win: win, handled: false };
// Inject paymentSuccess and paymentFailed methods into the document after
// its loaded.
win.addEventListener("DOMContentLoaded", function onDOMContentLoaded() {
win.removeEventListener("DOMContentLoaded", onDOMContentLoaded);
let browserElement = win.document.getElementById("content");
browserElement.
setAttribute("src", aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt);
browserElement.addEventListener("DOMWindowCreated",
function onDOMWindowCreated() {
browserElement.removeEventListener("DOMWindowCreated",
onDOMWindowCreated);
win.document.getElementById("content").contentDocument.defaultView
.wrappedJSObject.mozPaymentProvider = {
__exposedProps__: {
paymentSuccess: 'r',
paymentFailed: 'r'
},
paymentSuccess: paymentSuccess(aRequestId),
paymentFailed: paymentFailed(aRequestId)
};
}, true);
});
let winObserver = function(aClosedWin, aTopic) {
if (aTopic == "domwindowclosed") {
// Fail the payment if the window is closed.
if (aClosedWin == win) {
Services.ww.unregisterNotification(winObserver);
if (payments[aRequestId] && !payments[aRequestId].handled) {
aErrorCb.onresult(aRequestId, "USER_CANCELLED");
}
}
}
}
Services.ww.registerNotification(winObserver);
},
cleanup: function() {
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);
+169
View File
@@ -0,0 +1,169 @@
/* 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/. */
/* This module is imported at the startup of an application. It takes care of
* permissions installation, application url loading, security settings. Put
* stuff here that you want to happen once on startup before the webapp is
* loaded. */
this.EXPORTED_SYMBOLS = ["startup"];
const Ci = Components.interfaces;
const Cu = Components.utils;
/* We load here modules that are needed to perform the application startup.
* We lazily load modules that aren't needed on every startup.
* We load modules that aren't used here but that need to perform some
* initialization steps later in the startup function. */
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
// Lazily load these modules because we don't need them at every
// startup, but only during first run or runtime update.
XPCOMUtils.defineLazyModuleGetter(this, "PermissionsInstaller",
"resource://gre/modules/PermissionsInstaller.jsm");
const PROFILE_DIR = OS.Constants.Path.profileDir;
function isFirstRunOrUpdate() {
let savedBuildID = null;
try {
savedBuildID = Services.prefs.getCharPref("webapprt.buildID");
} catch (e) {}
let ourBuildID = Services.appinfo.platformBuildID;
if (ourBuildID != savedBuildID) {
Services.prefs.setCharPref("webapprt.buildID", ourBuildID);
return true;
}
return false;
}
function writeFile(aPath, aData) {
return Task.spawn(function() {
let data = new TextEncoder().encode(aData);
yield OS.File.writeAtomic(aPath, data, { tmpPath: aPath + ".tmp" });
});
}
function createBrandingFiles() {
return Task.spawn(function() {
let manifest = WebappRT.localeManifest;
let name = WebappRT.localeManifest.name;
let developer = " ";
if (WebappRT.localeManifest.developer) {
developer = WebappRT.localeManifest.developer.name;
}
let brandDTDContent = '<!ENTITY brandShortName "' + name + '">\n\
<!ENTITY brandFullName "' + name + '">\n\
<!ENTITY vendorShortName "' + developer + '">\n\
<!ENTITY trademarkInfo.part1 " ">';
yield writeFile(OS.Path.join(PROFILE_DIR, "brand.dtd"), brandDTDContent);
let brandPropertiesContent = 'brandShortName=' + name + '\n\
brandFullName=' + name + '\n\
vendorShortName=' + developer;
yield writeFile(OS.Path.join(PROFILE_DIR, "brand.properties"),
brandPropertiesContent);
});
}
// Observes all the events needed to actually launch an application.
// It waits for XUL window and webapps registry loading.
this.startup = function(window) {
return Task.spawn(function () {
// Observe XUL window loading.
// For tests, it could be already loaded.
let deferredWindowLoad = Promise.defer();
if (window.document && window.document.getElementById("content")) {
deferredWindowLoad.resolve();
} else {
window.addEventListener("DOMContentLoaded", function onLoad() {
window.removeEventListener("DOMContentLoaded", onLoad, false);
deferredWindowLoad.resolve();
});
}
let appUpdated = false;
let updatePending = yield WebappRT.isUpdatePending();
if (updatePending) {
appUpdated = yield WebappRT.applyUpdate();
}
yield WebappRT.configPromise;
let appData = WebappRT.config.app;
// Initialize DOMApplicationRegistry by importing Webapps.jsm.
Cu.import("resource://gre/modules/Webapps.jsm");
// Initialize window-independent handling of webapps- notifications.
Cu.import("resource://webapprt/modules/WebappManager.jsm");
// Wait for webapps registry loading.
yield DOMApplicationRegistry.registryStarted;
// Add the currently running app to the registry.
yield DOMApplicationRegistry.addInstalledApp(appData, appData.manifest,
appData.updateManifest);
let manifestURL = appData.manifestURL;
if (manifestURL) {
// On firstrun, set permissions to their default values.
// When the webapp runtime is updated, update the permissions.
if (isFirstRunOrUpdate(Services.prefs) || appUpdated) {
PermissionsInstaller.installPermissions(appData, true);
yield createBrandingFiles();
}
}
// Branding substitution
let aliasFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Ci.nsIFile);
aliasFile.initWithPath(PROFILE_DIR);
let aliasURI = Services.io.newFileURI(aliasFile);
Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler)
.setSubstitution("webappbranding", aliasURI);
// Wait for XUL window loading
yield deferredWindowLoad.promise;
// Load these modules here because they aren't needed right at startup,
// but they need to be loaded to perform some initialization steps.
Cu.import("resource://gre/modules/Payment.jsm");
Cu.import("resource://gre/modules/AlarmService.jsm");
Cu.import("resource://webapprt/modules/WebRTCHandler.jsm");
Cu.import("resource://webapprt/modules/DownloadView.jsm");
// Get the <browser> element in the webapp.xul window.
let appBrowser = window.document.getElementById("content");
// Set the principal to the correct appID and launch the application.
appBrowser.docShell.setIsApp(WebappRT.appID);
appBrowser.setAttribute("src", WebappRT.launchURI);
if (appData.manifest.fullscreen) {
appBrowser.addEventListener("load", function onLoad() {
appBrowser.removeEventListener("load", onLoad, true);
appBrowser.contentDocument.
documentElement.mozRequestFullScreen();
}, true);
}
WebappRT.startUpdateService();
});
}
+142
View File
@@ -0,0 +1,142 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["WebappManager"];
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Webapps.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/NativeApp.jsm");
Cu.import("resource://gre/modules/WebappOSUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
this.WebappManager = {
observe: function(aSubject, aTopic, aData) {
let data = JSON.parse(aData);
data.mm = aSubject;
let chromeWin;
switch (aTopic) {
case "webapps-ask-install":
chromeWin = Services.wm.getOuterWindowWithId(data.oid);
if (chromeWin)
this.doInstall(data, chromeWin);
break;
case "webapps-ask-uninstall":
chromeWin = Services.wm.getOuterWindowWithId(data.windowId);
if (chromeWin) {
this.doUninstall(data, chromeWin);
}
break;
case "webapps-launch":
WebappOSUtils.launch(data);
break;
case "webapps-uninstall":
WebappOSUtils.uninstall(data).then(null, Cu.reportError);
break;
}
},
update: function(aApp, aManifest, aZipPath) {
let nativeApp = new NativeApp(aApp, aManifest,
WebappRT.config.app.categories,
WebappRT.config.registryDir);
nativeApp.prepareUpdate(aApp, aManifest, aZipPath);
},
doInstall: function(data, window) {
let jsonManifest = data.isPackage ? data.app.updateManifest : data.app.manifest;
let manifest =
new ManifestHelper(jsonManifest, data.app.origin, data.app.manifestURL);
let name = manifest.name;
let bundle = Services.strings.createBundle("chrome://webapprt/locale/webapp.properties");
let choice = Services.prompt.confirmEx(
window,
bundle.formatStringFromName("webapps.install.title", [name], 1),
bundle.formatStringFromName("webapps.install.description", [name], 1),
// Set both buttons to strings with the cancel button being default
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
bundle.GetStringFromName("webapps.install.install"),
bundle.GetStringFromName("webapps.install.dontinstall"),
null,
null,
{});
// Perform the install if the user allows it
if (choice == 0) {
let nativeApp = new NativeApp(data.app, jsonManifest,
data.app.categories,
WebappRT.config.registryDir);
let localDir;
try {
localDir = nativeApp.createProfile();
} catch (ex) {
DOMApplicationRegistry.denyInstall(data);
return;
}
DOMApplicationRegistry.confirmInstall(data, localDir,
Task.async(function*(aApp, aManifest, aZipPath) {
yield nativeApp.install(aApp, aManifest, aZipPath);
})
);
} else {
DOMApplicationRegistry.denyInstall(data);
}
},
doUninstall: function(aData, aWindow) {
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
let manifest = new ManifestHelper(jsonManifest, aData.app.origin,
aData.app.manifestURL);
let name = manifest.name;
let bundle = Services.strings.createBundle("chrome://webapprt/locale/webapp.properties");
let choice = Services.prompt.confirmEx(
aWindow,
bundle.formatStringFromName("webapps.uninstall.title", [name], 1),
bundle.formatStringFromName("webapps.uninstall.description", [name], 1),
// Set both buttons to strings with the cancel button being default
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
bundle.GetStringFromName("webapps.uninstall.uninstall"),
bundle.GetStringFromName("webapps.uninstall.dontuninstall"),
null,
null,
{});
// Perform the uninstall if the user allows it
if (choice == 0) {
DOMApplicationRegistry.confirmUninstall(aData).then((aApp) => {
WebappOSUtils.uninstall(aApp).then(null, Cu.reportError);
});
} else {
DOMApplicationRegistry.denyUninstall(aData);
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference])
};
Services.obs.addObserver(WebappManager, "webapps-ask-install", false);
Services.obs.addObserver(WebappManager, "webapps-ask-uninstall", false);
Services.obs.addObserver(WebappManager, "webapps-launch", false);
Services.obs.addObserver(WebappManager, "webapps-uninstall", false);
Services.obs.addObserver(WebappManager, "webapps-update", false);
DOMApplicationRegistry.registerUpdateHandler(WebappManager.update);
+143
View File
@@ -0,0 +1,143 @@
/* 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/. */
this.EXPORTED_SYMBOLS = ["WebappRT"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, 'NativeApp',
'resource://gre/modules/NativeApp.jsm');
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
this.WebappRT = {
_configPromise: null,
get configPromise() {
if (!this._configPromise) {
this._configPromise = Task.spawn(function*() {
let webappJson = OS.Path.join(Services.dirsvc.get("AppRegD", Ci.nsIFile).path,
"webapp.json");
WebappRT.config = yield AppsUtils.loadJSONAsync(webappJson);
});
}
return this._configPromise;
},
get launchURI() {
return this.localeManifest.fullLaunchPath();
},
get localeManifest() {
return new ManifestHelper(this.config.app.manifest,
this.config.app.origin,
this.config.app.manifestURL);
},
get appID() {
let manifestURL = this.config.app.manifestURL;
if (!manifestURL) {
return Ci.nsIScriptSecurityManager.NO_APP_ID;
}
return appsService.getAppLocalIdByManifestURL(manifestURL);
},
isUpdatePending: Task.async(function*() {
let webappJson = OS.Path.join(Services.dirsvc.get("AppRegD", Ci.nsIFile).path,
"update", "webapp.json");
if (!(yield OS.File.exists(webappJson))) {
return false;
}
return true;
}),
applyUpdate: Task.async(function*() {
let webappJson = OS.Path.join(Services.dirsvc.get("AppRegD", Ci.nsIFile).path,
"update", "webapp.json");
let config = yield AppsUtils.loadJSONAsync(webappJson);
let nativeApp = new NativeApp(config.app, config.app.manifest,
config.app.categories,
config.registryDir);
try {
yield nativeApp.applyUpdate(config.app);
} catch (ex) {
return false;
}
// The update has been applied successfully, the new config file
// is the config file that was in the update directory.
this.config = config;
this._configPromise = Promise.resolve();
return true;
}),
startUpdateService: function() {
let manifestURL = this.config.app.manifestURL;
// We used to install apps without storing their manifest URL.
// Now we can't update them.
if (!manifestURL) {
return;
}
// Check for updates once a day.
let timerManager = Cc["@mozilla.org/updates/timer-manager;1"].
getService(Ci.nsIUpdateTimerManager);
timerManager.registerTimer("updateTimer", () => {
let window = Services.wm.getMostRecentWindow("webapprt:webapp");
window.navigator.mozApps.mgmt.getAll().onsuccess = function() {
let thisApp = null;
for (let app of this.result) {
if (app.manifestURL == manifestURL) {
thisApp = app;
break;
}
}
// This shouldn't happen if the app is installed.
if (!thisApp) {
Cu.reportError("Couldn't find the app in the webapps registry");
return;
}
thisApp.ondownloadavailable = () => {
// Download available, download it!
thisApp.download();
};
thisApp.ondownloadsuccess = () => {
// Update downloaded, apply it!
window.navigator.mozApps.mgmt.applyDownload(thisApp);
};
thisApp.ondownloadapplied = () => {
// Application updated, nothing to do.
};
thisApp.checkForUpdate();
}
}, Services.prefs.getIntPref("webapprt.app_update_interval"));
},
};
+17
View File
@@ -0,0 +1,17 @@
# CommandLineHandler.js
component {6d69c782-40a3-469b-8bfd-3ee366105a4a} CommandLineHandler.js
contract @mozilla.org/webapprt/clh;1 {6d69c782-40a3-469b-8bfd-3ee366105a4a}
category command-line-handler x-default @mozilla.org/webapprt/clh;1
# ContentPermission.js
component {07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4} ContentPermission.js
contract @mozilla.org/content-permission/prompt;1 {07ef5b2e-88fb-47bd-8cec-d3b0bef11ac4}
# DirectoryProvider.js
component {e1799fda-4b2f-4457-b671-e0641d95698d} DirectoryProvider.js
contract @mozilla.org/webapprt/directory-provider;1 {e1799fda-4b2f-4457-b671-e0641d95698d}
category xpcom-directory-providers webapprt-directory-provider @mozilla.org/webapprt/directory-provider;1
# PaymentUIGlue.js
component {ede1124f-72e8-4a31-9567-3270d46f21fb} PaymentUIGlue.js
contract @mozilla.org/payment/ui-glue;1 {ede1124f-72e8-4a31-9567-3270d46f21fb}
+1
View File
@@ -0,0 +1 @@
XPI_ROOT_APPID=webapprt@mozilla.org
+17
View File
@@ -0,0 +1,17 @@
# 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/.
webapprt.jar:
% content webapprt %content/
* content/webapp.js (content/webapp.js)
* content/webapp.xul (content/webapp.xul)
content/getUserMediaDialog.xul (content/getUserMediaDialog.xul)
content/getUserMediaDialog.js (content/getUserMediaDialog.js)
content/mochitest-shared.js (content/mochitest-shared.js)
content/mochitest.js (content/mochitest.js)
content/mochitest.xul (content/mochitest.xul)
* content/downloads/downloads.xul (content/downloads/downloads.xul)
content/downloads/downloads.js (content/downloads/downloads.js)
content/downloads/downloads.css (content/downloads/downloads.css)
content/downloads/download.xml (content/downloads/download.xml)
+59
View File
@@ -0,0 +1,59 @@
# -*- Mode: python; c-basic-offset: 4; 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 = ('Firefox', 'Webapp Runtime')
if CONFIG['OS_ARCH'] == 'WINNT':
DIRS += ['win']
elif CONFIG['OS_ARCH'] == 'Darwin':
DIRS += ['mac']
elif CONFIG['MOZ_ENABLE_GTK']:
DIRS += ['gtk']
DIRS += [
'locales',
'themes',
]
EXTRA_COMPONENTS += [
'CommandLineHandler.js',
'components.manifest',
'ContentPermission.js',
'DirectoryProvider.js',
'PaymentUIGlue.js',
]
EXTRA_JS_MODULES += [
'DownloadView.jsm',
'Startup.jsm',
'WebappManager.jsm',
'WebappRT.jsm',
'WebRTCHandler.jsm',
]
MOCHITEST_WEBAPPRT_CHROME_MANIFESTS += [
'test/chrome/downloads/webapprt.ini',
'test/chrome/webapprt.ini',
]
MOCHITEST_WEBAPPRT_CONTENT_MANIFESTS += ['test/content/webapprt.ini']
# Place webapprt resources in a separate app dir
DIST_SUBDIR = 'webapprt'
export('DIST_SUBDIR')
DEFINES['GRE_MILESTONE'] = CONFIG['GRE_MILESTONE']
DEFINES['MOZ_APP_BASENAME'] = CONFIG['MOZ_APP_BASENAME']
JAR_MANIFESTS += ['jar.mn']
JS_PREFERENCE_FILES += [
'prefs.js',
]
DIST_FILES += [
'webapprt.ini',
]
+97
View File
@@ -0,0 +1,97 @@
/* 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/. */
// Check for updates once a day.
pref("webapprt.app_update_interval", 86400);
pref("browser.chromeURL", "chrome://webapprt/content/webapp.xul");
pref("browser.download.folderList", 1);
// Disable all add-on locations other than the profile (which can't be disabled this way)
pref("extensions.enabledScopes", 1);
// Auto-disable any add-ons that are "dropped in" to the profile
pref("extensions.autoDisableScopes", 1);
// Disable add-on installation via the web-exposed APIs
pref("xpinstall.enabled", false);
// Disable installation of distribution add-ons
pref("extensions.installDistroAddons", false);
// Disable the add-on compatibility dialog
pref("extensions.showMismatchUI", false);
// Set reportURL for crashes
pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
// Blocklist preferences
pref("extensions.blocklist.enabled", true);
pref("extensions.blocklist.interval", 86400);
// Controls what level the blocklist switches from warning about items to forcibly
// blocking them.
pref("extensions.blocklist.level", 2);
pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
pref("full-screen-api.enabled", true);
// IndexedDB
pref("dom.indexedDB.enabled", true);
// Offline cache prefs
pref("browser.offline-apps.notify", false);
pref("browser.cache.offline.enable", true);
pref("offline-apps.allow_by_default", true);
// TCPSocket
pref("dom.mozTCPSocket.enabled", true);
// Enable smooth scrolling
pref("general.smoothScroll", true);
// WebPayment
pref("dom.mozPay.enabled", false);
// System messages
pref("dom.sysmsg.enabled", true);
// Alarm API
pref("dom.mozAlarms.enabled", true);
// Disable slow script dialog for apps
pref("dom.max_script_run_time", 0);
pref("dom.max_chrome_script_run_time", 0);
// The request URL of the GeoLocation backend
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#ifndef RELEASE_BUILD
// Enable mozPay default provider
pref("dom.payment.provider.0.name", "Firefox Marketplace");
pref("dom.payment.provider.0.description", "marketplace.firefox.com");
pref("dom.payment.provider.0.uri", "https://marketplace.firefox.com/mozpay/?req=");
pref("dom.payment.provider.0.type", "mozilla/payments/pay/v1");
pref("dom.payment.provider.0.requestMethod", "GET");
#endif
// Enable window resize and move
pref("dom.always_allow_move_resize_window", true);
// Disable all plugins. This has to be a non-empty string to disable plugins;
// otherwise, nsPluginHost::IsTypeWhitelisted assumes all plugins are enabled.
pref("plugin.allowed_types", " ");
// Suppress the check for outdated plugins from opening a window.
pref("extensions.blocklist.suppressUI", true);
// The default for this pref reflects whether the build is capable of IPC.
// (Turning it on in a no-IPC build will have no effect.)
#ifdef XP_MACOSX
// i386 ipc preferences
pref("dom.ipc.plugins.enabled.i386", false);
pref("dom.ipc.plugins.enabled.i386.flash player.plugin", true);
// x86_64 ipc preferences
pref("dom.ipc.plugins.enabled.x86_64", true);
#else
pref("dom.ipc.plugins.enabled", true);
#endif
pref("places.database.growthIncrementKiB", 0);
+28
View File
@@ -0,0 +1,28 @@
#if 0
; 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/.
#endif
#filter substitution
[App]
ID=webapprt@mozilla.org
Vendor=Mozilla
; Note: the Windows stub executable sets nsXREAppData::name to the webapp
; origin, overriding the value below, to make the app runner treat webapps
; as distinct products, per bug 747409.
Name=Webapp Runtime
Version=@GRE_MILESTONE@
BuildID=@MOZ_APP_BUILDID@
UAName=@MOZ_APP_BASENAME@
[Gecko]
MinVersion=@GRE_MILESTONE@
MaxVersion=@GRE_MILESTONE@
[Crash Reporter]
#if MOZILLA_OFFICIAL
Enabled=1
#endif
ServerURL=https://crash-reports.mozilla.com/submit?id=webapprt@mozilla.org&version=@GRE_MILESTONE@&buildid=@MOZ_APP_BUILDID@
+10 -12
View File
@@ -363,8 +363,8 @@ static const uint32_t EscapeChars[256] =
0,1023, 0, 512,1023, 0,1023, 112,1023,1023,1023,1023,1023,1023, 953, 784, // 2x !"#$%&'()*+,-./
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008,1008, 0,1008, 0, 768, // 3x 0123456789:;<=>?
1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 4x @ABCDEFGHIJKLMNO
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896, 896, 896, 896,1023, // 5x PQRSTUVWXYZ[\]^_
0,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 6x `abcdefghijklmno
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008, 896,1008, 896,1023, // 5x PQRSTUVWXYZ[\]^_
384,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 6x `abcdefghijklmno
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023, 0, // 7x pqrstuvwxyz{|}~ DEL
0 // 80 to FF are zero
};
@@ -551,28 +551,26 @@ NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags,
bool ignoreAscii = !!(aFlags & esc_OnlyNonASCII);
bool writing = !!(aFlags & esc_AlwaysCopy);
bool skipControl = !!(aFlags & esc_SkipControl);
bool skipInvalidHostChar = !!(aFlags & esc_Host);
const char* last = aStr;
const char* p = aStr;
for (int i = 0; i < aLen; ++i, ++p) {
//printf("%c [i=%d of aLen=%d]\n", *p, i, aLen);
if (*p == HEX_ESCAPE && i < aLen - 2) {
unsigned char* p1 = (unsigned char*)p + 1;
unsigned char* p2 = (unsigned char*)p + 2;
if (ISHEX(*p1) && ISHEX(*p2) &&
((*p1 < '8' && !ignoreAscii) || (*p1 >= '8' && !ignoreNonAscii)) &&
unsigned char c1 = *((unsigned char*)p + 1);
unsigned char c2 = *((unsigned char*)p + 2);
unsigned char u = (UNHEX(c1) << 4) + UNHEX(c2);
if (ISHEX(c1) && ISHEX(c2) &&
(!skipInvalidHostChar || dontNeedEscape(u, aFlags) || c1 >= '8') &&
((c1 < '8' && !ignoreAscii) || (c1 >= '8' && !ignoreNonAscii)) &&
!(skipControl &&
(*p1 < '2' || (*p1 == '7' && (*p2 == 'f' || *p2 == 'F'))))) {
//printf("- p1=%c p2=%c\n", *p1, *p2);
(c1 < '2' || (c1 == '7' && (c2 == 'f' || c2 == 'F'))))) {
writing = true;
if (p > last) {
//printf("- p=%p, last=%p\n", p, last);
aResult.Append(last, p - last);
last = p;
}
char u = (UNHEX(*p1) << 4) + UNHEX(*p2);
//printf("- u=%c\n", u);
aResult.Append(u);
i += 2;
p += 2;