diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index fecc31d7d50..afe06ae9dc7 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -444,6 +444,8 @@ pref("network.protocol-handler.external.ms-help", false); pref("network.protocol-handler.external.vnd.ms.radio", false); pref("network.protocol-handler.external.help", false); pref("network.protocol-handler.external.disk", false); +pref("network.protocol-handler.external.disks", false); +pref("network.protocol-handler.external.afp", false); // An exposed protocol handler is one that can be used in all contexts. A // non-exposed protocol handler is one that can only be used internally by the @@ -645,7 +647,7 @@ pref("security.directory", ""); pref("signed.applets.codebase_principal_support", false); pref("security.checkloaduri", true); pref("security.xpconnect.plugin.unrestricted", true); -// security-sensitive dialogs should delay focus. In milliseconds. +// security-sensitive dialogs should delay button enabling. In milliseconds. pref("security.dialog_enable_delay", 2000); // Modifier key prefs: default to Windows settings, diff --git a/xpfe/bootstrap/browser-prefs.js b/xpfe/bootstrap/browser-prefs.js index 773be437ee6..f7785950086 100644 --- a/xpfe/bootstrap/browser-prefs.js +++ b/xpfe/bootstrap/browser-prefs.js @@ -154,10 +154,11 @@ pref("news.directory", ""); pref("browser.editor.disabled", false); pref("spellchecker.dictionary", ""); -pref("autoupdate.enabled", true); pref("xpinstall.dialog.confirm", "chrome://communicator/content/xpinstall/institems.xul"); pref("xpinstall.dialog.progress", "chrome://communicator/content/xpinstall/xpistatus.xul"); pref("xpinstall.dialog.progress.type", ""); +pref("xpinstall.whitelist.add", "mozilla.org, mozdev.org, texturizer.net"); +pref("xpinstall.blacklist.add", ""); // Customizable toolbar stuff pref("custtoolbar.personal_toolbar_folder", ""); diff --git a/xpinstall/public/nsIDOMInstallTriggerGlobal.h b/xpinstall/public/nsIDOMInstallTriggerGlobal.h index cc953ffe945..8304d499f5e 100644 --- a/xpinstall/public/nsIDOMInstallTriggerGlobal.h +++ b/xpinstall/public/nsIDOMInstallTriggerGlobal.h @@ -60,7 +60,7 @@ public: EQUAL = 0 }; - NS_IMETHOD UpdateEnabled(PRBool* aReturn)=0; + NS_IMETHOD UpdateEnabled(nsIScriptGlobalObject* aGlobalObject, PRBool* aReturn)=0; NS_IMETHOD Install(nsIScriptGlobalObject* globalObject, nsXPITriggerInfo* aInfo, PRBool* aReturn)=0; diff --git a/xpinstall/public/nsISoftwareUpdate.h b/xpinstall/public/nsISoftwareUpdate.h index 7c4b57d08b7..43d7b0e004c 100644 --- a/xpinstall/public/nsISoftwareUpdate.h +++ b/xpinstall/public/nsISoftwareUpdate.h @@ -57,10 +57,9 @@ #define NS_IXPINSTALLCOMPONENT_CLASSNAME "Mozilla XPInstall Component" #define XPINSTALL_ENABLE_PREF "xpinstall.enabled" -#define XPINSTALL_MANUAL_CONFIRM "xpinstall.manual_confirm" -#define XPINSTALL_NOTIFICATIONS_ENABLE "xpinstall.notifications.enabled" //TODO: this needs to be fixed at some point. -#define XPINSTALL_NOTIFICATIONS_LASTDATE "xpinstall.notifications.lastDate" //TODO: this needs to be fixed at some point. -#define XPINSTALL_NOTIFICATIONS_INTERVAL "xpinstall.notifications.interval" //TODO: this needs to be fixed at some point. +#define XPINSTALL_WHITELIST_ADD "xpinstall.whitelist.add" +#define XPINSTALL_WHITELIST_REQUIRED "xpinstall.whitelist.required" +#define XPINSTALL_BLACKLIST_ADD "xpinstall.blacklist.add" #define XPI_NO_NEW_THREAD 0x1000 diff --git a/xpinstall/public/xpinstall.js b/xpinstall/public/xpinstall.js index 00b8df77cf0..06427335e78 100644 --- a/xpinstall/public/xpinstall.js +++ b/xpinstall/public/xpinstall.js @@ -1,6 +1,2 @@ pref("xpinstall.enabled", true); -pref("xpinstall.manual_confirm", true); - -pref("xpinstall.notifications.enabled", true); -pref("xpinstall.notifications.interval", 1); -pref("xpinstall.notifications.lastDate", 0); +pref("xpinstall.whitelist.required", true); diff --git a/xpinstall/src/Makefile.in b/xpinstall/src/Makefile.in index 313af9298e1..f85188b9992 100644 --- a/xpinstall/src/Makefile.in +++ b/xpinstall/src/Makefile.in @@ -76,6 +76,8 @@ REQUIRES = xpcom \ plugin \ unicharutil \ appshell \ + docshell \ + cookie \ layout \ $(ZLIB_REQUIRES) \ $(NULL) diff --git a/xpinstall/src/nsInstallTrigger.cpp b/xpinstall/src/nsInstallTrigger.cpp index 1ab47cf309e..9d9cc8ae251 100644 --- a/xpinstall/src/nsInstallTrigger.cpp +++ b/xpinstall/src/nsInstallTrigger.cpp @@ -50,6 +50,12 @@ #include "nsIPrefBranch.h" #include "nsIPrefService.h" +#include "nsIPermissionManager.h" +#include "nsIDocShell.h" +#include "nsNetUtil.h" +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsIPrincipal.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" @@ -112,85 +118,303 @@ nsInstallTrigger::SetScriptObject(void *aScriptObject) NS_IMETHODIMP nsInstallTrigger::HandleContent(const char * aContentType, nsIInterfaceRequestor* aWindowContext, - nsIRequest* request) + nsIRequest* aRequest) { nsresult rv = NS_OK; - if (!request) return NS_ERROR_NULL_POINTER; + if (!aRequest) + return NS_ERROR_NULL_POINTER; - if (nsCRT::strcasecmp(aContentType, "application/x-xpinstall") == 0) { - nsCOMPtr uri; - nsCOMPtr aChannel = do_QueryInterface(request); - rv = aChannel->GetURI(getter_AddRefs(uri)); - if (NS_FAILED(rv)) return rv; - - request->Cancel(NS_BINDING_ABORTED); - - if (uri) { - nsCAutoString spec; - rv = uri->GetSpec(spec); - if (NS_FAILED(rv)) - return NS_ERROR_NULL_POINTER; - - nsCOMPtr globalObjectOwner = do_QueryInterface(aWindowContext); - if (globalObjectOwner) - { - nsCOMPtr globalObject; - globalObjectOwner->GetScriptGlobalObject(getter_AddRefs(globalObject)); - if (globalObject) - { - PRBool value; - rv = StartSoftwareUpdate(globalObject, NS_ConvertUTF8toUCS2(spec), 0, &value); - - if (NS_SUCCEEDED(rv) && value) - return NS_OK; - } - } - } - } else { - // The content-type was not application/x-xpinstall + if (nsCRT::strcasecmp(aContentType, "application/x-xpinstall") != 0) + { + // We only support content-type application/x-xpinstall return NS_ERROR_WONT_HANDLE_CONTENT; } - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsInstallTrigger::UpdateEnabled(PRBool* aReturn) -{ - nsCOMPtr prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); - - if ( prefBranch ) + // Save the URI so nsXPInstallManager can re-load it later + nsCOMPtr uri; + nsCAutoString urispec; + nsCOMPtr channel = do_QueryInterface(aRequest); + if (channel) { - nsresult rv = prefBranch->GetBoolPref( (const char*) XPINSTALL_ENABLE_PREF, aReturn); + rv = channel->GetURI(getter_AddRefs(uri)); + if (NS_SUCCEEDED(rv) && uri) + rv = uri->GetSpec(urispec); + } + if (NS_FAILED(rv)) + return rv; + if (urispec.IsEmpty()) + return NS_ERROR_ILLEGAL_VALUE; - if (NS_FAILED(rv)) + +#ifdef NS_DEBUG + // XXX: if only the owner weren't always null this is what I'd want to do + + // Get the owner of the channel to perform permission checks. + // + // It's OK if owner is null, this means it was a top level + // load and we want to allow installs in that case. + nsCOMPtr owner; + nsCOMPtr principal; + nsCOMPtr ownerURI; + + channel->GetOwner( getter_AddRefs( owner ) ); + if ( owner ) + { + principal = do_QueryInterface( owner ); + if ( principal ) { - *aReturn = PR_FALSE; + principal->GetURI( getter_AddRefs( ownerURI ) ); } } +#endif + + // Save the referrer if any, for permission checks + PRBool trustReferrer = PR_FALSE; + nsCOMPtr referringURI; + nsCOMPtr httpChannel(do_QueryInterface(channel)); + if ( httpChannel ) + { + httpChannel->GetReferrer(getter_AddRefs(referringURI)); + + // see if we should trust the referrer (which can be null): + // - we are an httpChannel (we are if we're here) + // - user has not turned off the feature + PRInt32 referrerLevel = 0; + nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if ( prefBranch) + { + rv = prefBranch->GetIntPref( (const char*)"network.http.sendRefererHeader", + &referrerLevel ); + trustReferrer = ( NS_SUCCEEDED(rv) && (referrerLevel >= 2) ); + } + } + + + // Cancel the current request. nsXPInstallManager restarts the download + // under its control (shared codepath with InstallTrigger) + aRequest->Cancel(NS_BINDING_ABORTED); + + + // Get the global object of the target window for StartSoftwareUpdate + nsCOMPtr globalObject; + nsCOMPtr globalObjectOwner = + do_QueryInterface(aWindowContext); + if ( globalObjectOwner ) + { + globalObjectOwner->GetScriptGlobalObject(getter_AddRefs(globalObject)); + } + if ( !globalObject ) + return NS_ERROR_INVALID_ARG; + + + // We have what we need to start an XPInstall, now figure out if we are + // going to honor this request based on PermissionManager settings + PRBool enabled = PR_FALSE; + + if ( trustReferrer ) + { + // easiest and most common case: base decision on http referrer + // + // NOTE: the XPI itself may be from elsewhere; the user can decide if + // they trust the actual source when they get the install confirmation + // dialog. The decision we're making here is whether the triggering + // site is one which is allowed to annoy the user with modal dialogs + + enabled = AllowInstall( referringURI ); + } else { - // no prefs manager: we're in the install wizard and always work - *aReturn = PR_TRUE; + // Now we're stumbing in the dark. In the most likely case the user + // simply clicked on an FTP link (no referrer) and it's perfectly + // sane to use the current window. + // + // On the other hand the user might be opening a non-http XPI link + // in an unrelated existing window (typed in location bar, bookmark, + // dragged link ...) in which case the current window is irrelevant. + // If we knew it was one of these explicit user actions we'd like to + // allow it, but we have no way of knowing that here. + // + // But there's no way to distinguish the innocent cases from a clever + // malicious site. If we used the target window then evil.com could + // embed a presumed allowed site (e.g. mozilla.org) in a frame, then + // change the location to the XPI and trigger the install. Or evil.com + // could do the same thing in a new window (more work to get around + // popup blocking, but possible). + // + // Our choices appear to be block this type of load entirely or to + // trust only the install URI. The former is unacceptably restrictive, + // the latter allows malicious sites to pester people with modal + // dialogs. As long as the trusted sites don't host bad content that's + // no worse than an endless stream of alert()s -- already possible. + // If the trusted sites don't even have an ftp server then even this + // level of annoyance is not possible. + // + // If a trusted site hosts an install with an exploitable flaw it + // might be possible that a malicious site would attempt to trick + // people into installing it, hoping to turn around and exploit it. + // This is not entirely far-fetched (it's been done with ActiveX + // controls) and will require community policing of the default + // trusted sites. + + enabled = AllowInstall( uri ); + } + + + if ( enabled ) + { + rv = StartSoftwareUpdate( globalObject, + NS_ConvertUTF8toUTF16(urispec), + 0, + &enabled); + } + else + { + // TODO: fire event signaling blocked Install attempt + rv = NS_ERROR_ABORT; + } + + return rv; +} + + +// updateWhitelist +// +// Helper function called by nsInstallTrigger::AllowInstall(). +// Interprets the pref as a comma-delimited list of hosts and adds each one +// to the permission manager using the given action. Clear pref when done. +static void updatePermissions( const char* aPref, + PRUint32 aPermission, + nsIPermissionManager* aPermissionManager, + nsIPrefBranch* aPrefBranch) +{ + NS_PRECONDITION(aPref && aPermissionManager && aPrefBranch, "Null arguments!"); + + nsXPIDLCString hostlist; + nsresult rv = aPrefBranch->GetCharPref( aPref, getter_Copies(hostlist)); + if (NS_SUCCEEDED(rv) && !hostlist.IsEmpty()) + { + nsCAutoString host; + PRInt32 start=0, match=0; + nsresult rv; + nsCOMPtr uri; + + do { + match = hostlist.FindChar(',', start); + + host = Substring(hostlist, start, match-start); + host.CompressWhitespace(); + host.Insert("http://", 0); + + rv = NS_NewURI(getter_AddRefs(uri), host); + if (NS_SUCCEEDED(rv)) + { + aPermissionManager->Add( uri, XPI_PERMISSION, aPermission ); + } + start = match+1; + } while ( match > 0 ); + + // save empty list, we don't need to do this again + aPrefBranch->SetCharPref( aPref, ""); + } +} + + +// Check whether an Install is allowed. The launching URI can be null, +// in which case only the global pref-setting matters. +PRBool +nsInstallTrigger::AllowInstall(nsIURI* aLaunchURI) +{ + // Check the global setting. + PRBool xpiEnabled = PR_FALSE; + nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if ( !prefBranch) + { + return PR_TRUE; // no pref service in native install, it's OK + } + + prefBranch->GetBoolPref( XPINSTALL_ENABLE_PREF, &xpiEnabled); + if ( !xpiEnabled ) + { + // globally turned off + return PR_FALSE; + } + + + // Check permissions for the launching host if we have one + nsCOMPtr permissionMgr = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + + if ( permissionMgr && aLaunchURI ) + { + PRBool isChrome = PR_FALSE; + PRBool isFile = PR_FALSE; + aLaunchURI->SchemeIs( "chrome", &isChrome ); + aLaunchURI->SchemeIs( "file", &isFile ); + + // file: and chrome: don't need whitelisted hosts + if ( !isChrome && !isFile ) + { + // check prefs for permission updates before testing URI + updatePermissions( XPINSTALL_WHITELIST_ADD, + nsIPermissionManager::ALLOW_ACTION, + permissionMgr, prefBranch ); + updatePermissions( XPINSTALL_BLACKLIST_ADD, + nsIPermissionManager::DENY_ACTION, + permissionMgr, prefBranch ); + + PRBool requireWhitelist = PR_TRUE; + prefBranch->GetBoolPref( XPINSTALL_WHITELIST_REQUIRED, &requireWhitelist ); + + PRUint32 permission = nsIPermissionManager::UNKNOWN_ACTION; + permissionMgr->TestPermission( aLaunchURI, XPI_PERMISSION, &permission ); + + if ( permission == nsIPermissionManager::DENY_ACTION ) + { + xpiEnabled = PR_FALSE; + } + else if ( requireWhitelist && + permission != nsIPermissionManager::ALLOW_ACTION ) + { + xpiEnabled = PR_FALSE; + } + } + } + + return xpiEnabled; +} + + +NS_IMETHODIMP +nsInstallTrigger::UpdateEnabled(nsIScriptGlobalObject* aGlobalObject, PRBool* aReturn) +{ + *aReturn = PR_FALSE; + NS_ENSURE_ARG_POINTER(aGlobalObject); + + // find the current site + nsCOMPtr domdoc; + nsCOMPtr window(do_QueryInterface(aGlobalObject)); + if ( window ) + { + window->GetDocument(getter_AddRefs(domdoc)); + nsCOMPtr doc(do_QueryInterface(domdoc)); + if ( doc ) + { + *aReturn = AllowInstall( doc->GetDocumentURI() ); + } } return NS_OK; } + + NS_IMETHODIMP nsInstallTrigger::Install(nsIScriptGlobalObject* aGlobalObject, nsXPITriggerInfo* aTrigger, PRBool* aReturn) { NS_ASSERTION(aReturn, "Invalid pointer arg"); *aReturn = PR_FALSE; - PRBool enabled; - nsresult rv = UpdateEnabled(&enabled); - if (NS_FAILED(rv) || !enabled) - { - delete aTrigger; - return NS_OK; - } - + nsresult rv; nsXPInstallManager *mgr = new nsXPInstallManager(); if (mgr) { @@ -218,15 +442,9 @@ nsInstallTrigger::InstallChrome(nsIScriptGlobalObject* aGlobalObject, PRUint32 a *aReturn = PR_FALSE; - // make sure we're allowing installs - PRBool enabled; - nsresult rv = UpdateEnabled(&enabled); - if (NS_FAILED(rv) || !enabled) - return NS_OK; - - // The Install manager will delete itself when done, once we've called // InitManager. Before then **WE** must delete it + nsresult rv = NS_ERROR_OUT_OF_MEMORY; nsXPInstallManager *mgr = new nsXPInstallManager(); if (mgr) { @@ -252,14 +470,9 @@ nsInstallTrigger::InstallChrome(nsIScriptGlobalObject* aGlobalObject, PRUint32 a NS_IMETHODIMP nsInstallTrigger::StartSoftwareUpdate(nsIScriptGlobalObject* aGlobalObject, const nsString& aURL, PRInt32 aFlags, PRBool* aReturn) { - PRBool enabled; nsresult rv = NS_ERROR_OUT_OF_MEMORY; *aReturn = PR_FALSE; - UpdateEnabled(&enabled); - if (!enabled) - return NS_OK; - // The Install manager will delete itself when done, once we've called // InitManager. Before then **WE** must delete it nsXPInstallManager *mgr = new nsXPInstallManager(); @@ -317,12 +530,6 @@ nsInstallTrigger::CompareVersion(const nsString& aRegName, nsIDOMInstallVersion* { *aReturn = NOT_FOUND; // assume failure. - PRBool enabled; - - UpdateEnabled(&enabled); - if (!enabled) - return NS_OK; - VERSION cVersion; NS_ConvertUCS2toUTF8 regName(aRegName); REGERR status; @@ -350,12 +557,6 @@ nsInstallTrigger::CompareVersion(const nsString& aRegName, nsIDOMInstallVersion* NS_IMETHODIMP nsInstallTrigger::GetVersion(const nsString& component, nsString& version) { - PRBool enabled; - - UpdateEnabled(&enabled); - if (!enabled) - return NS_OK; - VERSION cVersion; NS_ConvertUCS2toUTF8 regName(component); REGERR status; diff --git a/xpinstall/src/nsInstallTrigger.h b/xpinstall/src/nsInstallTrigger.h index fa92f0a4592..289a142a08b 100644 --- a/xpinstall/src/nsInstallTrigger.h +++ b/xpinstall/src/nsInstallTrigger.h @@ -26,6 +26,8 @@ #define CHROME_DELAYED 0x10 #define CHROME_SELECT 0x20 +#define XPI_PERMISSION "install" + class nsInstallTrigger: public nsIScriptObjectOwner, public nsIDOMInstallTriggerGlobal, public nsIContentHandler @@ -42,7 +44,7 @@ class nsInstallTrigger: public nsIScriptObjectOwner, NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject); NS_IMETHOD SetScriptObject(void* aScriptObject); - NS_IMETHOD UpdateEnabled(PRBool* aReturn); + NS_IMETHOD UpdateEnabled(nsIScriptGlobalObject* aGlobalObject, PRBool* aReturn); NS_IMETHOD Install(nsIScriptGlobalObject* aGlobalObject, nsXPITriggerInfo *aInfo, PRBool* aReturn); NS_IMETHOD InstallChrome(nsIScriptGlobalObject* aGlobalObject, PRUint32 aType, nsXPITriggerItem* aItem, PRBool* aReturn); NS_IMETHOD StartSoftwareUpdate(nsIScriptGlobalObject* aGlobalObject, const nsString& aURL, PRInt32 aFlags, PRInt32* aReturn); @@ -53,6 +55,7 @@ class nsInstallTrigger: public nsIScriptObjectOwner, private: + PRBool AllowInstall(nsIURI* aLaunchURI); void *mScriptObject; }; diff --git a/xpinstall/src/nsJSInstallTriggerGlobal.cpp b/xpinstall/src/nsJSInstallTriggerGlobal.cpp index fe6bace7ab9..3383512d4b2 100644 --- a/xpinstall/src/nsJSInstallTriggerGlobal.cpp +++ b/xpinstall/src/nsJSInstallTriggerGlobal.cpp @@ -48,6 +48,8 @@ #include "nsXPITriggerInfo.h" #include "nsIComponentManager.h" +#include "nsNetUtil.h" +#include "nsIScriptSecurityManager.h" #include "nsSoftwareUpdateIIDs.h" @@ -132,16 +134,23 @@ PR_STATIC_CALLBACK(JSBool) InstallTriggerGlobalUpdateEnabled(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsIDOMInstallTriggerGlobal *nativeThis = (nsIDOMInstallTriggerGlobal*)JS_GetPrivate(cx, obj); - PRBool nativeRet = PR_FALSE; *rval = JSVAL_FALSE; if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) return JS_TRUE; - nativeThis->UpdateEnabled(&nativeRet); - *rval = BOOLEAN_TO_JSVAL(nativeRet); - return JS_TRUE; + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + + PRBool nativeRet = PR_FALSE; + if (globalObject) + nativeThis->UpdateEnabled(globalObject, &nativeRet); + + *rval = BOOLEAN_TO_JSVAL(nativeRet); + return JS_TRUE; } // @@ -155,33 +164,40 @@ InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *arg *rval = JSVAL_FALSE; if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) - return JS_FALSE; + return JS_TRUE; // make sure XPInstall is enabled, return false if not + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + PRBool enabled = PR_FALSE; - nativeThis->UpdateEnabled(&enabled); - if (!enabled) + nativeThis->UpdateEnabled(globalObject, &enabled); + if (!enabled || !globalObject) return JS_TRUE; // get window.location to construct relative URLs - nsString baseURL; + nsCOMPtr baseURL; JSObject* global = JS_GetGlobalObject(cx); if (global) { jsval v; if (JS_GetProperty(cx,global,"location",&v)) { - ConvertJSValToStr( baseURL, cx, v ); - PRInt32 lastslash = baseURL.RFindChar('/'); - if (lastslash != kNotFound) - { - baseURL.Truncate(lastslash+1); - } + nsAutoString location; + ConvertJSValToStr( location, cx, v ); + NS_NewURI(getter_AddRefs(baseURL), location); } } + // if we can't create a security manager we might be in the wizard, allow + PRBool abortLoad = PR_FALSE; + nsCOMPtr secman( + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); + // parse associative array of installs if ( argc >= 1 && JSVAL_IS_OBJECT(argv[0]) ) @@ -197,43 +213,69 @@ InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *arg const PRUnichar *name, *URL; const PRUnichar *iconURL = nsnull; - for (int i = 0; i < ida->length; i++ ) + for (int i = 0; i < ida->length && !abortLoad; i++ ) { JS_IdToValue( cx, ida->vector[i], &v ); name = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v ) )); + URL = iconURL = nsnull; JS_GetUCProperty( cx, JSVAL_TO_OBJECT(argv[0]), NS_REINTERPRET_CAST(const jschar*, name), nsCRT::strlen(name), &v ); if ( JSVAL_IS_OBJECT(v) ) { - jsval v2; - JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "URL", &v2 ); - URL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v2 ) )); + if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "URL", &v2 )) + URL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v2 ) )); - JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "IconURL", &v2 ); - iconURL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v2 ) )); + if (JS_GetProperty( cx, JSVAL_TO_OBJECT(v), "IconURL", &v2 )) + iconURL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v2 ) )); } - else + else { - URL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v ) )); + URL = NS_REINTERPRET_CAST(const PRUnichar*, JS_GetStringChars( JS_ValueToString( cx, v ) )); } if ( name && URL ) { - nsXPITriggerItem *item = new nsXPITriggerItem( name, URL, iconURL ); + // Get relative URL to load + nsAutoString xpiURL(URL); + if (baseURL) + { + nsCAutoString resolvedURL; + baseURL->Resolve(NS_ConvertUTF16toUTF8(xpiURL), resolvedURL); + xpiURL = NS_ConvertUTF8toUTF16(resolvedURL); + } + + // Make sure we're allowed to load this URL + if (secman) + { + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), xpiURL); + if (NS_SUCCEEDED(rv)) + { + rv = secman->CheckLoadURIFromScript(cx, uri); + if (NS_FAILED(rv)) + abortLoad = PR_TRUE; + } + } + + nsAutoString icon(iconURL); + if (iconURL && baseURL) + { + nsCAutoString resolvedIcon; + baseURL->Resolve(NS_ConvertUTF16toUTF8(icon), resolvedIcon); + icon = NS_ConvertUTF8toUTF16(resolvedIcon); + } + + nsXPITriggerItem *item = new nsXPITriggerItem( name, xpiURL.get(), icon.get() ); if ( item ) { - if ( item->IsRelativeURL() ) - { - item->mURL.Insert( baseURL, 0 ); - } trigger->Add( item ); } else - ; // XXX signal error somehow + abortLoad = PR_TRUE; } else - ; // XXX need to signal error + abortLoad = PR_TRUE; } JS_DestroyIdArray( cx, ida ); } @@ -242,30 +284,20 @@ InstallTriggerGlobalInstall(JSContext *cx, JSObject *obj, uintN argc, jsval *arg // save callback function if any (ignore bad args for now) if ( argc >= 2 && JS_TypeOfValue(cx,argv[1]) == JSTYPE_FUNCTION ) { - trigger->SaveCallback( cx, argv[1] ); + trigger->SaveCallback( cx, argv[1] ); } // pass on only if good stuff found - if (trigger->Size() > 0) + if (!abortLoad && trigger->Size() > 0) { PRBool result; - - nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); - if (scriptContext) - { - nsIScriptGlobalObject *globalObject = - scriptContext->GetGlobalObject(); - if (globalObject) - { - nativeThis->Install(globalObject, trigger, &result); - *rval = BOOLEAN_TO_JSVAL(result); - return JS_TRUE; - } - } + nativeThis->Install(globalObject, trigger, &result); + *rval = BOOLEAN_TO_JSVAL(result); + return JS_TRUE; } - else - delete trigger; + // didn't pass it on so we must delete trigger + delete trigger; } JS_ReportError(cx, "Incorrect arguments to InstallTrigger.Install()"); @@ -280,39 +312,40 @@ PR_STATIC_CALLBACK(JSBool) InstallTriggerGlobalInstallChrome(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsIDOMInstallTriggerGlobal *nativeThis = (nsIDOMInstallTriggerGlobal*)JS_GetPrivate(cx, obj); - PRBool nativeRet; uint32 chromeType; - nsAutoString baseURL; nsAutoString sourceURL; nsAutoString name; *rval = JSVAL_FALSE; if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) { - return JS_FALSE; + return JS_TRUE; } // make sure XPInstall is enabled, return if not + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + PRBool enabled = PR_FALSE; - nativeThis->UpdateEnabled(&enabled); - if (!enabled) + nativeThis->UpdateEnabled(globalObject, &enabled); + if (!enabled || !globalObject) return JS_TRUE; // get window.location to construct relative URLs + nsCOMPtr baseURL; JSObject* global = JS_GetGlobalObject(cx); if (global) { jsval v; if (JS_GetProperty(cx,global,"location",&v)) { - ConvertJSValToStr( baseURL, cx, v ); - PRInt32 lastslash = baseURL.RFindChar('/'); - if (lastslash != kNotFound) - { - baseURL.Truncate(lastslash+1); - } + nsAutoString location; + ConvertJSValToStr( location, cx, v ); + NS_NewURI(getter_AddRefs(baseURL), location); } } @@ -323,6 +356,29 @@ InstallTriggerGlobalInstallChrome(JSContext *cx, JSObject *obj, uintN argc, jsva ConvertJSValToStr(sourceURL, cx, argv[1]); ConvertJSValToStr(name, cx, argv[2]); + if (baseURL) + { + nsCAutoString resolvedURL; + baseURL->Resolve(NS_ConvertUTF16toUTF8(sourceURL), resolvedURL); + sourceURL = NS_ConvertUTF8toUTF16(resolvedURL); + } + + // Make sure caller is allowed to load this url. + // if we can't create a security manager we might be in the wizard, allow + nsCOMPtr secman( + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); + if (secman) + { + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), sourceURL); + if (NS_SUCCEEDED(rv)) + { + rv = secman->CheckLoadURIFromScript(cx, uri); + if (NS_FAILED(rv)) + return JS_FALSE; + } + } + if ( chromeType & CHROME_ALL ) { // there's at least one known chrome type @@ -330,27 +386,8 @@ InstallTriggerGlobalInstallChrome(JSContext *cx, JSObject *obj, uintN argc, jsva sourceURL.get(), nsnull); - if (item && item->IsRelativeURL()) - item->mURL.Insert( baseURL, 0 ); - - nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); - - if (scriptContext) - { - nsIScriptGlobalObject *globalObject = - scriptContext->GetGlobalObject(); - if (globalObject) - { - nsresult rv = nativeThis->InstallChrome(globalObject, chromeType, item, &nativeRet); - if (NS_FAILED(rv)) - return JS_FALSE; - } - else - return JS_FALSE; - } - else - return JS_FALSE; - + PRBool nativeRet = PR_FALSE; + nativeThis->InstallChrome(globalObject, chromeType, item, &nativeRet); *rval = BOOLEAN_TO_JSVAL(nativeRet); } } @@ -366,44 +403,76 @@ InstallTriggerGlobalStartSoftwareUpdate(JSContext *cx, JSObject *obj, uintN argc { nsIDOMInstallTriggerGlobal *nativeThis = (nsIDOMInstallTriggerGlobal*)JS_GetPrivate(cx, obj); PRBool nativeRet; - nsAutoString b0; - PRInt32 b1 = 0; + PRInt32 flags = 0; *rval = JSVAL_FALSE; if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) - return JS_FALSE; + return JS_TRUE; + // make sure XPInstall is enabled, return if not + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + + PRBool enabled = PR_FALSE; + nativeThis->UpdateEnabled(globalObject, &enabled); + if (!enabled || !globalObject) + return JS_TRUE; + + // get window.location to construct relative URLs + nsCOMPtr baseURL; + JSObject* global = JS_GetGlobalObject(cx); + if (global) + { + jsval v; + if (JS_GetProperty(cx,global,"location",&v)) + { + nsAutoString location; + ConvertJSValToStr( location, cx, v ); + NS_NewURI(getter_AddRefs(baseURL), location); + } + } + + if ( argc >= 1 ) { - ConvertJSValToStr(b0, cx, argv[0]); + nsAutoString xpiURL; + ConvertJSValToStr(xpiURL, cx, argv[0]); + if (baseURL) + { + nsCAutoString resolvedURL; + baseURL->Resolve(NS_ConvertUTF16toUTF8(xpiURL), resolvedURL); + xpiURL = NS_ConvertUTF8toUTF16(resolvedURL); + } - if (argc >= 2 && !JS_ValueToInt32(cx, argv[1], (int32 *)&b1)) + // Make sure caller is allowed to load this url. + // if we can't create a security manager we might be in the wizard, allow + nsCOMPtr secman( + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); + if (secman) + { + nsCOMPtr uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), xpiURL); + if (NS_SUCCEEDED(rv)) + { + rv = secman->CheckLoadURIFromScript(cx, uri); + if (NS_FAILED(rv)) + return JS_FALSE; + } + } + + if (argc >= 2 && !JS_ValueToInt32(cx, argv[1], (int32 *)&flags)) { JS_ReportError(cx, "StartSoftwareUpdate() 2nd parameter must be a number"); return JS_FALSE; } - nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); - - if (scriptContext) + if(NS_OK == nativeThis->StartSoftwareUpdate(globalObject, xpiURL, flags, &nativeRet)) { - nsIScriptGlobalObject *globalObject = - scriptContext->GetGlobalObject(); - if (globalObject) - { - if(NS_OK != nativeThis->StartSoftwareUpdate(globalObject, b0, b1, &nativeRet)) - { - return JS_FALSE; - } - } - else - return JS_FALSE; + *rval = BOOLEAN_TO_JSVAL(nativeRet); } - else - return JS_FALSE; - - *rval = BOOLEAN_TO_JSVAL(nativeRet); } else { @@ -422,15 +491,29 @@ PR_STATIC_CALLBACK(JSBool) InstallTriggerGlobalCompareVersion(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsIDOMInstallTriggerGlobal *nativeThis = (nsIDOMInstallTriggerGlobal*)JS_GetPrivate(cx, obj); - PRInt32 nativeRet; nsAutoString regname; nsAutoString version; int32 major,minor,release,build; - *rval = JSVAL_NULL; + // In case of error or disabled return NOT_FOUND + PRInt32 nativeRet = nsIDOMInstallTriggerGlobal::NOT_FOUND; + *rval = INT_TO_JSVAL(nativeRet); if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) - return JS_FALSE; + return JS_TRUE; + + + // make sure XPInstall is enabled, return if not + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + + PRBool enabled = PR_FALSE; + nativeThis->UpdateEnabled(globalObject, &enabled); + if (!enabled) + return JS_TRUE; + if (argc < 2 ) { @@ -511,23 +594,32 @@ InstallTriggerGlobalGetVersion(JSContext *cx, JSObject *obj, uintN argc, jsval * nsAutoString regname; nsAutoString version; + // In case of error return a null value *rval = JSVAL_NULL; if (nsnull == nativeThis && (JS_FALSE == CreateNativeObject(cx, obj, &nativeThis)) ) - return JS_FALSE; + return JS_TRUE; + + + // make sure XPInstall is enabled, return if not + nsIScriptGlobalObject *globalObject = nsnull; + nsIScriptContext *scriptContext = GetScriptContextFromJSContext(cx); + if (scriptContext) + globalObject = scriptContext->GetGlobalObject(); + + PRBool enabled = PR_FALSE; + nativeThis->UpdateEnabled(globalObject, &enabled); + if (!enabled) + return JS_TRUE; + // get the registry name argument ConvertJSValToStr(regname, cx, argv[0]); - if(NS_OK != nativeThis->GetVersion(regname, version)) + if(nativeThis->GetVersion(regname, version) == NS_OK && !version.IsEmpty() ) { - return JS_FALSE; - } - - if(version.IsEmpty()) - *rval = JSVAL_NULL; - else ConvertStrToJSVal(version, cx, rval); + } return JS_TRUE; }