forked from mirrors/gecko-dev
This is adding in the new Windows 11 only version of taskbar pinning. For the new pinning to work, we need to use limited access feature tokens. Those are going to be made private and aren't included with this change. This change will compile, and will work if built against the correct limited access feature tokens, as specified in developer local machine config files, but for every other build, the new taskbar pinning won't work and will fall back to the old methods. I will implement the try / release building machines using the secret limited access feature tokens in a follow-up diff. Differential Revision: https://phabricator.services.mozilla.com/D205004
237 lines
7.5 KiB
C++
237 lines
7.5 KiB
C++
/* -*- 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 <wrl.h>
|
|
# include <inspectable.h>
|
|
# include <roapi.h>
|
|
# include <windows.services.store.h>
|
|
# include <windows.foundation.h>
|
|
|
|
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<int, mozilla::SequentiallyConsistent>;
|
|
|
|
mozilla::Result<bool, HRESULT> Unlock(
|
|
Win11LimitedAccessFeatureType feature) override;
|
|
|
|
private:
|
|
AtomicState& GetState(Win11LimitedAccessFeatureType feature);
|
|
mozilla::Result<bool, HRESULT> 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<Win11LimitedAccessFeaturesInterface>
|
|
CreateWin11LimitedAccessFeaturesInterface() {
|
|
RefPtr<Win11LimitedAccessFeaturesInterface> result(
|
|
new Win11LimitedAccessFeatures());
|
|
return result;
|
|
}
|
|
|
|
mozilla::Result<bool, HRESULT> 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<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
|
|
Win11LimitedAccessFeatureType feature) {
|
|
ComPtr<ILimitedAccessFeaturesStatics> limitedAccessFeatures;
|
|
ComPtr<ILimitedAccessFeatureRequestResult> 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<int>(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<Win11LimitedAccessFeaturesInterface>
|
|
CreateWin11LimitedAccessFeaturesInterface() {
|
|
RefPtr<Win11LimitedAccessFeaturesInterface> result;
|
|
return result;
|
|
}
|
|
|
|
#endif
|