/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 file exists so that LaunchModernSettingsDialogDefaultApps can be called * without linking to libxul. */ #include "Windows11LimitedAccessFeatures.h" // MINGW32 is not supported for these features // Fall back function defined in the #else #ifndef __MINGW32__ # include "nsString.h" # include "nsWindowsHelpers.h" # include "mozilla/Atomics.h" # include # include # include # include # include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::ApplicationModel; struct LimitedAccessFeatureInfo { const WCHAR* feature; const WCHAR* token; const WCHAR* attestation; }; /** * To unlock features, we need a feature identifier, a token, and an * attestation string. The token is generated by Microsoft and must * match the publisher id Microsoft thinks we have. * * To get a token, find the right microsoft email address by doing * a search on the web for the feature you want unlocked and reach * out to the right people at Microsoft. * * The token is generated from Microsoft. * The jumbled code in the attestation string is a publisher id and * must match the code in the resources / .rc file for the identity * looking like this: * * Identity LimitedAccessFeature {{ L"MozillaFirefox_pcsmm0jrprpb2" }} * * That is injected into our build in create_rc.py and is necessary * to unlock the taskbar pinning feature / APIs from an unpackaged * build. * * Note that we keep our tokens secret. They are stored on our secrets * cluster and picked up by our continuous build machines * when they build and are injected below via define. * * For the taskbar, MOZ_WINDOWS_TASKBAR_PINNING_API_KEY is registered * in the moz.build file for this, driven by the build environment config. * * The matching value in the build environment config is declared in two * places: * 1) in toolkit/moz.configure, which registers that it exists but doesn't * set it's value * 2) in win32, win64 and win64-aarch/common-opt files, which tell the * system where to get the files from, via: * * ac_add_options --with-windows-taskbar-pinning-api-keyfile=${APIKEYDIR}/windows-laf-tokens.data * * The file with the data is pulled down by the build infrastructure and * only by the build infrastructure. To see all of the places where that * data is used by the CI system, do a searchfox for windows-laf-tokens.data. * In order to unlock a feature locally, if you know the product name * and token, you can store it in a file with the following format. * * PRODUCT_NAME TOKEN * * And that's it. No white space before, no white space or newlines or comments after. * Assuming you stored the above in browser/branding/nightly/windows-taskbar-pinning-api.key, * then you can add a line like this to your mozconfig file: * * ac_add_options --with-windows-taskbar-pinning-api-keyfile=@TOPSRCDIR@/browser/branding/nightly/windows-taskbar-pinning-api.key * * And then when you recompile and run, the taskbar-pinning apis for * Windows 11 will then work. * */ static LimitedAccessFeatureInfo limitedAccessFeatureInfo[] = {{ // Win11LimitedAccessFeatureType::Taskbar MOZ_WINDOWS_TASKBAR_PINNING_API_FEATURE, MOZ_WINDOWS_TASKBAR_PINNING_API_KEY, MOZ_WINDOWS_TASKBAR_PINNING_API_ATTRIBUTION, }}; /** Implementation of the Win11LimitedAccessFeaturesInterface. */ class Win11LimitedAccessFeatures : public Win11LimitedAccessFeaturesInterface { public: using AtomicState = mozilla::Atomic; mozilla::Result Unlock( Win11LimitedAccessFeatureType feature) override; private: AtomicState& GetState(Win11LimitedAccessFeatureType feature); mozilla::Result UnlockImplementation( Win11LimitedAccessFeatureType feature); /** * Store the state as an atomic so that it can be safely accessed from * different threads. */ static AtomicState mTaskbarState; static AtomicState mDefaultState; enum State { Uninitialized, Locked, Unlocked, }; }; Win11LimitedAccessFeatures::AtomicState Win11LimitedAccessFeatures::mTaskbarState( Win11LimitedAccessFeatures::Uninitialized); Win11LimitedAccessFeatures::AtomicState Win11LimitedAccessFeatures::mDefaultState( Win11LimitedAccessFeatures::Uninitialized); RefPtr CreateWin11LimitedAccessFeaturesInterface() { RefPtr result( new Win11LimitedAccessFeatures()); return result; } mozilla::Result Win11LimitedAccessFeatures::Unlock( Win11LimitedAccessFeatureType feature) { AtomicState& atomicState = GetState(feature); int state = atomicState; if (state != Uninitialized) { return (state == Unlocked); } // If multiple threads read the state at the same time, and it's unitialized, // both threads will unlock the feature. This situation is unlikely, but even // if it happens, it's not a problem. auto result = UnlockImplementation(feature); int newState = Locked; if (!result.isErr() && result.unwrap()) { newState = Unlocked; } atomicState = newState; return result; } Win11LimitedAccessFeatures::AtomicState& Win11LimitedAccessFeatures::GetState( Win11LimitedAccessFeatureType feature) { switch (feature) { case Win11LimitedAccessFeatureType::Taskbar: return mTaskbarState; default: MOZ_ASSERT(false, "Unhandled feature type! Add a new atomic state variable, add " "that entry to the switch statement above, and add the proper " "entries for the feature and the token."); return mDefaultState; } } mozilla::Result Win11LimitedAccessFeatures::UnlockImplementation( Win11LimitedAccessFeatureType feature) { ComPtr limitedAccessFeatures; ComPtr limitedAccessFeaturesResult; HRESULT hr = RoGetActivationFactory( HStringReference( RuntimeClass_Windows_ApplicationModel_LimitedAccessFeatures) .Get(), IID_ILimitedAccessFeaturesStatics, &limitedAccessFeatures); if (!SUCCEEDED(hr)) { return mozilla::Err(hr); } const auto& lafInfo = limitedAccessFeatureInfo[static_cast(feature)]; hr = limitedAccessFeatures->TryUnlockFeature( HStringReference(lafInfo.feature).Get(), HStringReference(lafInfo.token).Get(), HStringReference(lafInfo.attestation).Get(), &limitedAccessFeaturesResult); if (!SUCCEEDED(hr)) { return mozilla::Err(hr); } LimitedAccessFeatureStatus status; hr = limitedAccessFeaturesResult->get_Status(&status); if (!SUCCEEDED(hr)) { return mozilla::Err(hr); } int state = Unlocked; if ((status != LimitedAccessFeatureStatus_Available) && (status != LimitedAccessFeatureStatus_AvailableWithoutToken)) { state = Locked; } return (state == Unlocked); } #else // MINGW32 implementation RefPtr CreateWin11LimitedAccessFeaturesInterface() { RefPtr result; return result; } #endif