forked from mirrors/gecko-dev
267 lines
8.6 KiB
C++
267 lines
8.6 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"
|
|
|
|
#include "mozilla/Logging.h"
|
|
|
|
static mozilla::LazyLogModule sLog("Windows11LimitedAccessFeatures");
|
|
|
|
#define LAF_LOG(level, msg, ...) MOZ_LOG(sLog, level, (msg, ##__VA_ARGS__))
|
|
|
|
// 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;
|
|
|
|
using namespace mozilla;
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
struct LimitedAccessFeatureInfo {
|
|
const char* debugName;
|
|
const WCHAR* feature;
|
|
const WCHAR* token;
|
|
const WCHAR* attestation;
|
|
};
|
|
|
|
static LimitedAccessFeatureInfo limitedAccessFeatureInfo[] = {{
|
|
"Win11LimitedAccessFeatureType::Taskbar",
|
|
MOZ_WINDOWS_TASKBAR_PINNING_API_FEATURE,
|
|
MOZ_WINDOWS_TASKBAR_PINNING_API_KEY,
|
|
MOZ_WINDOWS_TASKBAR_PINNING_API_ATTRIBUTION,
|
|
}};
|
|
|
|
static_assert(mozilla::ArrayLength(limitedAccessFeatureInfo) ==
|
|
kWin11LimitedAccessFeatureTypeCount);
|
|
|
|
/**
|
|
Implementation of the Win11LimitedAccessFeaturesInterface.
|
|
*/
|
|
class Win11LimitedAccessFeatures : public Win11LimitedAccessFeaturesInterface {
|
|
public:
|
|
using AtomicState = Atomic<int, SequentiallyConsistent>;
|
|
|
|
Result<bool, HRESULT> Unlock(Win11LimitedAccessFeatureType feature) override;
|
|
|
|
private:
|
|
AtomicState& GetState(Win11LimitedAccessFeatureType feature);
|
|
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;
|
|
}
|
|
|
|
Result<bool, HRESULT> Win11LimitedAccessFeatures::Unlock(
|
|
Win11LimitedAccessFeatureType feature) {
|
|
AtomicState& atomicState = GetState(feature);
|
|
|
|
const auto& lafInfo = limitedAccessFeatureInfo[static_cast<int>(feature)];
|
|
|
|
LAF_LOG(
|
|
LogLevel::Debug, "Limited Access Feature Info for %s. Feature %S, %S, %S",
|
|
lafInfo.debugName, lafInfo.feature, lafInfo.token, lafInfo.attestation);
|
|
|
|
int state = atomicState;
|
|
if (state != Uninitialized) {
|
|
LAF_LOG(LogLevel::Debug, "%s already initialized! State = %s",
|
|
lafInfo.debugName, (state == Unlocked) ? "true" : "false");
|
|
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:
|
|
LAF_LOG(LogLevel::Debug, "Missing feature type for %d",
|
|
static_cast<int>(feature));
|
|
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;
|
|
}
|
|
}
|
|
|
|
Result<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
|
|
Win11LimitedAccessFeatureType feature) {
|
|
ComPtr<ILimitedAccessFeaturesStatics> limitedAccessFeatures;
|
|
ComPtr<ILimitedAccessFeatureRequestResult> limitedAccessFeaturesResult;
|
|
|
|
const auto& lafInfo = limitedAccessFeatureInfo[static_cast<int>(feature)];
|
|
|
|
HRESULT hr = RoGetActivationFactory(
|
|
HStringReference(
|
|
RuntimeClass_Windows_ApplicationModel_LimitedAccessFeatures)
|
|
.Get(),
|
|
IID_ILimitedAccessFeaturesStatics, &limitedAccessFeatures);
|
|
|
|
if (!SUCCEEDED(hr)) {
|
|
LAF_LOG(LogLevel::Debug, "%s activation error. HRESULT = 0x%lx",
|
|
lafInfo.debugName, hr);
|
|
return Err(hr);
|
|
}
|
|
|
|
hr = limitedAccessFeatures->TryUnlockFeature(
|
|
HStringReference(lafInfo.feature).Get(),
|
|
HStringReference(lafInfo.token).Get(),
|
|
HStringReference(lafInfo.attestation).Get(),
|
|
&limitedAccessFeaturesResult);
|
|
if (!SUCCEEDED(hr)) {
|
|
LAF_LOG(LogLevel::Debug, "%s unlock error. HRESULT = 0x%lx",
|
|
lafInfo.debugName, hr);
|
|
return Err(hr);
|
|
}
|
|
|
|
LimitedAccessFeatureStatus status;
|
|
hr = limitedAccessFeaturesResult->get_Status(&status);
|
|
if (!SUCCEEDED(hr)) {
|
|
LAF_LOG(LogLevel::Debug, "%s get status error. HRESULT = 0x%lx",
|
|
lafInfo.debugName, hr);
|
|
return Err(hr);
|
|
}
|
|
|
|
int state = Unlocked;
|
|
if ((status != LimitedAccessFeatureStatus_Available) &&
|
|
(status != LimitedAccessFeatureStatus_AvailableWithoutToken)) {
|
|
LAF_LOG(LogLevel::Debug, "%s not available. HRESULT = 0x%lx",
|
|
lafInfo.debugName, hr);
|
|
state = Locked;
|
|
}
|
|
|
|
return (state == Unlocked);
|
|
}
|
|
|
|
#else // MINGW32 implementation
|
|
|
|
RefPtr<Win11LimitedAccessFeaturesInterface>
|
|
CreateWin11LimitedAccessFeaturesInterface() {
|
|
RefPtr<Win11LimitedAccessFeaturesInterface> result;
|
|
return result;
|
|
}
|
|
|
|
#endif
|