/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Extension Manager. * * The Initial Developer of the Original Code is * the Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Dave Townsend * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "amInstallTrigger.h" #include "nsIClassInfoImpl.h" #include "nsIGenericFactory.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" #include "nsICategoryManager.h" #include "nsServiceManagerUtils.h" #include "nsXPIDLString.h" #include "nsIScriptNameSpaceManager.h" #include "nsDOMJSUtils.h" #include "nsIXPConnect.h" #include "nsContentUtils.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsNetUtil.h" #include "nsIScriptSecurityManager.h" // // Helper function for URI verification // static nsresult CheckLoadURIFromScript(JSContext *aCx, const nsACString& aUriStr) { nsresult rv; nsCOMPtr secman(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); // get the script principal nsCOMPtr principal; rv = secman->GetSubjectPrincipal(getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); if (!principal) return NS_ERROR_FAILURE; // convert the requested URL string to a URI // Note that we use a null base URI here, since that's what we use when we // actually convert the string into a URI to load. nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), aUriStr); NS_ENSURE_SUCCESS(rv, rv); // are we allowed to load this one? rv = secman->CheckLoadURIWithPrincipal(principal, uri, nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL); return rv; } NS_IMPL_ISUPPORTS1_CI(amInstallTrigger, amIInstallTrigger) amInstallTrigger::amInstallTrigger() { mManager = do_GetService("@mozilla.org/addons/integration;1"); } amInstallTrigger::~amInstallTrigger() { } JSContext* amInstallTrigger::GetJSContext() { nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID()); // get the xpconnect native call context nsAXPCNativeCallContext *cc = nsnull; xpc->GetCurrentNativeCallContext(&cc); if (!cc) return nsnull; // Get JSContext of current call JSContext* cx; nsresult rv = cc->GetJSContext(&cx); if (NS_FAILED(rv)) return nsnull; return cx; } already_AddRefed amInstallTrigger::GetOriginatingWindow(JSContext* aCx) { nsIScriptGlobalObject *globalObject = nsnull; nsIScriptContext *scriptContext = GetScriptContextFromJSContext(aCx); if (!scriptContext) return nsnull; globalObject = scriptContext->GetGlobalObject(); if (!globalObject) return nsnull; nsCOMPtr window = do_QueryInterface(globalObject); return window.forget(); } already_AddRefed amInstallTrigger::GetOriginatingURI(nsIDOMWindowInternal* aWindow) { if (!aWindow) return nsnull; nsCOMPtr domdoc; aWindow->GetDocument(getter_AddRefs(domdoc)); nsCOMPtr doc(do_QueryInterface(domdoc)); nsIURI* uri = doc->GetDocumentURI(); NS_IF_ADDREF(uri); return uri; } /* boolean updateEnabled (); */ NS_IMETHODIMP amInstallTrigger::UpdateEnabled(PRBool *_retval NS_OUTPARAM) { return Enabled(_retval); } /* boolean enabled (); */ NS_IMETHODIMP amInstallTrigger::Enabled(PRBool *_retval NS_OUTPARAM) { nsCOMPtr window = GetOriginatingWindow(GetJSContext()); nsCOMPtr referer = GetOriginatingURI(window); return mManager->IsInstallEnabled(NS_LITERAL_STRING("application/x-xpinstall"), referer, _retval); } /* boolean install (in nsIVariant args, [optional] in amIInstallCallback callback); */ NS_IMETHODIMP amInstallTrigger::Install(nsIVariant *aArgs, amIInstallCallback *aCallback, PRBool *_retval NS_OUTPARAM) { JSContext *cx = GetJSContext(); nsCOMPtr window = GetOriginatingWindow(cx); nsCOMPtr referer = GetOriginatingURI(window); jsval params; nsresult rv = aArgs->GetAsJSVal(¶ms); NS_ENSURE_SUCCESS(rv, rv); if (!JSVAL_IS_OBJECT(params) || !JSVAL_TO_OBJECT(params)) return NS_ERROR_INVALID_ARG; JSIdArray *ida = JS_Enumerate(cx, JSVAL_TO_OBJECT(params)); if (!ida) return NS_ERROR_FAILURE; PRUint32 count = ida->length; nsTArray names; nsTArray uris; nsTArray icons; nsTArray hashes; jsval v; for (PRUint32 i = 0; i < count; i++ ) { JS_IdToValue(cx, ida->vector[i], &v); JSString *str = JS_ValueToString(cx, v); if (!str) { JS_DestroyIdArray(cx, ida); return NS_ERROR_FAILURE; } const PRUnichar* name = reinterpret_cast(JS_GetStringChars(str)); const PRUnichar* uri = nsnull; const PRUnichar* icon = nsnull; const PRUnichar* hash = nsnull; JS_GetUCProperty(cx, JSVAL_TO_OBJECT(params), reinterpret_cast(name), nsCRT::strlen(name), &v); if (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v)) { jsval v2; if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "URL", &v2) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { JS_DestroyIdArray(cx, ida); return NS_ERROR_FAILURE; } uri = reinterpret_cast(JS_GetStringChars(str)); } if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "IconURL", &v2) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { JS_DestroyIdArray(cx, ida); return NS_ERROR_FAILURE; } icon = reinterpret_cast(JS_GetStringChars(str)); } if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "Hash", &v2) && !JSVAL_IS_VOID(v2)) { JSString *str = JS_ValueToString(cx, v2); if (!str) { JS_DestroyIdArray(cx, ida); return NS_ERROR_FAILURE; } hash = reinterpret_cast(JS_GetStringChars(str)); } } else { uri = reinterpret_cast(JS_GetStringChars(JS_ValueToString(cx, v))); } if (!uri) { JS_DestroyIdArray(cx, ida); return NS_ERROR_FAILURE; } nsCString tmpURI = NS_ConvertUTF16toUTF8(uri); // Get relative URL to load if (referer) { rv = referer->Resolve(tmpURI, tmpURI); if (NS_FAILED(rv)) { JS_DestroyIdArray(cx, ida); return rv; } } rv = CheckLoadURIFromScript(cx, tmpURI); if (NS_FAILED(rv)) { JS_DestroyIdArray(cx, ida); return rv; } uri = UTF8ToNewUnicode(tmpURI); if (icon) { nsCString tmpIcon = NS_ConvertUTF16toUTF8(icon); if (referer) { rv = referer->Resolve(tmpIcon, tmpIcon); if (NS_FAILED(rv)) { JS_DestroyIdArray(cx, ida); return rv; } } // If the page can't load the icon then just ignore it rv = CheckLoadURIFromScript(cx, tmpIcon); if (NS_FAILED(rv)) icon = nsnull; else icon = UTF8ToNewUnicode(tmpIcon); } names.AppendElement(name); uris.AppendElement(uri); icons.AppendElement(icon); hashes.AppendElement(hash); } JS_DestroyIdArray(cx, ida); rv = mManager->InstallAddonsFromWebpage(NS_LITERAL_STRING("application/x-xpinstall"), window, referer, uris.Elements(), hashes.Elements(), names.Elements(), icons.Elements(), aCallback, count, _retval); for (PRUint32 i = 0; i < uris.Length(); i++) { NS_Free(const_cast(uris[i])); if (icons[i]) NS_Free(const_cast(icons[i])); } return rv; } /* boolean installChrome (in PRUint32 type, in AString url, in AString skin); */ NS_IMETHODIMP amInstallTrigger::InstallChrome(PRUint32 aType, const nsAString & aUrl, const nsAString & aSkin, PRBool *_retval NS_OUTPARAM) { return StartSoftwareUpdate(aUrl, 0, _retval); } /* boolean startSoftwareUpdate (in AString url, [optional] in PRInt32 flags); */ NS_IMETHODIMP amInstallTrigger::StartSoftwareUpdate(const nsAString & aUrl, PRInt32 aFlags, PRBool *_retval NS_OUTPARAM) { nsresult rv; JSContext *cx = GetJSContext(); nsCOMPtr window = GetOriginatingWindow(cx); nsCOMPtr referer = GetOriginatingURI(window); nsTArray names; nsTArray uris; nsTArray icons; nsTArray hashes; nsCString tmpURI = NS_ConvertUTF16toUTF8(aUrl); // Get relative URL to load if (referer) { rv = referer->Resolve(tmpURI, tmpURI); NS_ENSURE_SUCCESS(rv, rv); } rv = CheckLoadURIFromScript(cx, tmpURI); NS_ENSURE_SUCCESS(rv, rv); names.AppendElement((PRUnichar*)nsnull); uris.AppendElement(UTF8ToNewUnicode(tmpURI)); icons.AppendElement((PRUnichar*)nsnull); hashes.AppendElement((PRUnichar*)nsnull); rv = mManager->InstallAddonsFromWebpage(NS_LITERAL_STRING("application/x-xpinstall"), window, referer, uris.Elements(), hashes.Elements(), names.Elements(), icons.Elements(), nsnull, 1, _retval); NS_Free(const_cast(uris[0])); return rv; } NS_DECL_CLASSINFO(amInstallTrigger) NS_GENERIC_FACTORY_CONSTRUCTOR(amInstallTrigger) static NS_METHOD RegisterInstallTrigger(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *aRegistryLocation, const char *aComponentType, const nsModuleComponentInfo *aInfo) { nsresult rv = NS_OK; nsCOMPtr catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsXPIDLCString previous; rv = catman->AddCategoryEntry(JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, "InstallTrigger", AM_INSTALLTRIGGER_CONTRACTID, PR_TRUE, PR_TRUE, getter_Copies(previous)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } // The list of components we register static const nsModuleComponentInfo components[] = { { "InstallTrigger Component", AM_InstallTrigger_CID, AM_INSTALLTRIGGER_CONTRACTID, amInstallTriggerConstructor, RegisterInstallTrigger, nsnull, // unregister nsnull, // factory destructor NS_CI_INTERFACE_GETTER_NAME(amInstallTrigger), nsnull, // language helper &NS_CLASSINFO_NAME(amInstallTrigger), nsIClassInfo::DOM_OBJECT // flags } }; NS_IMPL_NSGETMODULE(AddonsModule, components)