mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
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:
@@ -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
@@ -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.
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
bool aIsContent,
|
||||
bool aUsePrivateBrowsing,
|
||||
bool aUseRemoteTabs,
|
||||
OriginAttributes& aAttrs)
|
||||
const OriginAttributes& aAttrs)
|
||||
: mTopFrameElement(do_GetWeakReference(aTopFrameElement))
|
||||
, mNestedFrameId(0)
|
||||
, mIsContent(aIsContent)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -121,9 +121,6 @@ public:
|
||||
{ }
|
||||
#endif
|
||||
|
||||
void
|
||||
SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor);
|
||||
|
||||
void
|
||||
ClearBackgroundActor()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -46,3 +46,6 @@ DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wshadow']
|
||||
|
||||
DIST_FILES += [
|
||||
'greprefs.js',
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 *,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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"),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
interface nsICookie2;
|
||||
interface nsIFile;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Additions to the frozen nsICookieManager
|
||||
*/
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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]();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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+"'");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
@@ -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]);
|
||||
@@ -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]);
|
||||
@@ -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();
|
||||
@@ -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
|
||||
@@ -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]);
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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"));
|
||||
},
|
||||
};
|
||||
@@ -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}
|
||||
@@ -0,0 +1 @@
|
||||
XPI_ROOT_APPID=webapprt@mozilla.org
|
||||
@@ -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)
|
||||
@@ -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',
|
||||
]
|
||||
@@ -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);
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user