Merge branch 'main' into dev/migrie/oop/3/feanor-and-the-unchaining-of-melkor

This commit is contained in:
Mike Griese
2023-03-20 10:54:55 -05:00
19 changed files with 174 additions and 113 deletions

View File

@@ -193,7 +193,6 @@ chh
chk
CHT
Cic
CLA
Clcompile
CLE
cleartype
@@ -480,7 +479,6 @@ defterm
DELAYLOAD
DELETEONRELEASE
Delt
demoable
depersist
deprioritized
deserializers
@@ -537,7 +535,6 @@ DSSCL
DSwap
DTest
DTTERM
DUMMYUNIONNAME
dup'ed
dvi
dwl
@@ -590,7 +587,6 @@ ETW
EUDC
EVENTID
eventing
everytime
evflags
evt
execd
@@ -802,7 +798,6 @@ HIBYTE
hicon
HIDEWINDOW
hinst
Hirots
HISTORYBUFS
HISTORYNODUP
HISTORYSIZE
@@ -903,7 +898,6 @@ INSERTMODE
INTERACTIVITYBASE
INTERCEPTCOPYPASTE
INTERNALNAME
inthread
intsafe
INVALIDARG
INVALIDATERECT
@@ -1260,14 +1254,12 @@ ntm
nto
ntrtl
ntstatus
ntsubauth
NTSYSCALLAPI
nttree
nturtl
ntuser
NTVDM
ntverp
NTWIN
nugetversions
nullability
nullness
@@ -1306,8 +1298,6 @@ opencode
opencon
openconsole
openconsoleproxy
OPENIF
OPENLINK
openps
openvt
ORIGINALFILENAME
@@ -1360,9 +1350,7 @@ pcg
pch
PCIDLIST
PCIS
PCLIENT
PCLONG
PCOBJECT
pcon
PCONSOLE
PCONSOLEENDTASK
@@ -1374,7 +1362,6 @@ pcshell
PCSHORT
PCSR
PCSTR
PCUNICODE
PCWCH
PCWCHAR
PCWSTR
@@ -1423,7 +1410,6 @@ PLOGICAL
pnm
PNMLINK
pntm
PNTSTATUS
POBJECT
Podcast
POINTSLIST
@@ -1442,7 +1428,6 @@ ppf
ppguid
ppidl
PPROC
PPROCESS
ppropvar
ppsi
ppsl
@@ -1506,7 +1491,6 @@ ptrs
ptsz
PTYIn
PUCHAR
PUNICODE
pwch
PWDDMCONSOLECONTEXT
pws
@@ -1568,7 +1552,6 @@ REGISTEROS
REGISTERVDM
regkey
REGSTR
reingest
RELBINPATH
remoting
renamer
@@ -1863,6 +1846,7 @@ TDP
TEAMPROJECT
tearoff
Teb
Techo
tellp
teraflop
terminalcore
@@ -2005,7 +1989,6 @@ unittesting
unittests
unk
unknwn
unmark
UNORM
unparseable
unregistering

27
.github/workflows/winget.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Publish to Winget
on:
release:
types: [published]
env:
REGEX: 'Microsoft\.WindowsTerminal(?:Preview)?_Win10_([\d.]+)_8wekyb3d8bbwe\.msixbundle$'
jobs:
publish:
runs-on: windows-latest # Action can only run on Windows
steps:
- name: Extract version from release asset
id: extract-version
run: |
$version = '${{ toJSON(github.event.release.assets.*.name) }}' | ConvertFrom-Json | Select-String -Pattern $env:REGEX | ForEach-Object { $_.Matches.Groups[1].Value }
Write-Output "version=$version" >> $env:GITHUB_OUTPUT
- name: Publish ${{ github.event.release.prerelease && 'Preview' || 'Stable' }}
uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: Microsoft.WindowsTerminal${{ github.event.release.prerelease && '.Preview' || '' }}
version: ${{ steps.extract-version.outputs.version }}
installers-regex: ${{ env.REGEX }}
token: ${{ secrets.WINGET_TOKEN }}
fork-user: DHowett

View File

@@ -133,7 +133,12 @@ namespace winrt::TerminalApp::implementation
// cause you to chase down the rabbit hole of "why is App not
// registered?" when it definitely is.
_isElevated = ::Microsoft::Console::Utils::IsElevated();
// The TerminalPage has to be constructed during our construction, to
// make sure that there's a terminal page for callers of
// SetTitleBarContent
_isElevated = ::Microsoft::Console::Utils::IsRunningElevated();
_canDragDrop = ::Microsoft::Console::Utils::CanUwpDragDrop();
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
if (auto self{ weakSelf.get() })
@@ -164,10 +169,14 @@ namespace winrt::TerminalApp::implementation
// - <none> - reports internal state
// Return Value:
// - True if elevated, false otherwise.
bool AppLogic::IsElevated() const noexcept
bool AppLogic::IsRunningElevated() const noexcept
{
return _isElevated;
}
bool AppLogic::CanDragDrop() const noexcept
{
return _canDragDrop;
}
// Method Description:
// - Called by UWP context invoker to let us know that we may have to change some of our behaviors

View File

@@ -49,7 +49,8 @@ namespace winrt::TerminalApp::implementation
void Create();
bool IsUwp() const noexcept;
void RunAsUwp();
bool IsElevated() const noexcept;
bool IsRunningElevated() const noexcept;
bool CanDragDrop() const noexcept;
void ReloadSettings();
bool HasSettingsStartupActions() const noexcept;
@@ -77,6 +78,7 @@ namespace winrt::TerminalApp::implementation
private:
bool _isUwp{ false };
bool _isElevated{ false };
bool _canDragDrop{ false };
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };

View File

@@ -31,7 +31,8 @@ namespace TerminalApp
Boolean IsUwp();
void RunAsUwp();
Boolean IsElevated();
Boolean IsRunningElevated();
Boolean CanDragDrop();
Boolean HasSettingsStartupActions();

View File

@@ -128,27 +128,26 @@ namespace winrt::TerminalApp::implementation
_systemRowsToScroll = _ReadSystemRowsToScroll();
}
bool TerminalPage::IsElevated() const noexcept
bool TerminalPage::IsRunningElevated() const noexcept
{
// use C++11 magic statics to make sure we only do this once.
// This won't change over the lifetime of the application
static const auto isElevated = []() {
// *** THIS IS A SINGLETON ***
auto result = false;
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
try
{
result = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsElevated();
}
CATCH_LOG();
return result;
}();
return isElevated;
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
try
{
return Application::Current().as<TerminalApp::App>().Logic().IsRunningElevated();
}
CATCH_LOG();
return false;
}
bool TerminalPage::CanDragDrop() const noexcept
{
try
{
return Application::Current().as<TerminalApp::App>().Logic().CanDragDrop();
}
CATCH_LOG();
return true;
}
void TerminalPage::Create()
@@ -161,11 +160,11 @@ namespace winrt::TerminalApp::implementation
_tabView = _tabRow.TabView();
_rearranging = false;
const auto isElevated = IsElevated();
const auto canDragDrop = CanDragDrop();
_tabRow.PointerMoved({ get_weak(), &TerminalPage::_RestorePointerCursorHandler });
_tabView.CanReorderTabs(!isElevated);
_tabView.CanDragTabs(!isElevated);
_tabView.CanReorderTabs(canDragDrop);
_tabView.CanDragTabs(canDragDrop);
_tabView.TabDragStarting({ get_weak(), &TerminalPage::_TabDragStarted });
_tabView.TabDragCompleted({ get_weak(), &TerminalPage::_TabDragCompleted });
@@ -284,7 +283,7 @@ namespace winrt::TerminalApp::implementation
// Setup mouse vanish attributes
SystemParametersInfoW(SPI_GETMOUSEVANISH, 0, &_shouldMouseVanish, false);
_tabRow.ShowElevationShield(IsElevated() && _settings.GlobalSettings().ShowAdminShield());
_tabRow.ShowElevationShield(IsRunningElevated() && _settings.GlobalSettings().ShowAdminShield());
// Store cursor, so we can restore it, e.g., after mouse vanishing
// (we'll need to adapt this logic once we make cursor context aware)
@@ -311,7 +310,7 @@ namespace winrt::TerminalApp::implementation
// GH#12267: Don't forget about defterm handoff here. If we're being
// created for embedding, then _yea_, we don't need to handoff to an
// elevated window.
if (!_startupActions || IsElevated() || _shouldStartInboundListener || _startupActions.Size() == 0)
if (!_startupActions || IsRunningElevated() || _shouldStartInboundListener || _startupActions.Size() == 0)
{
// there aren't startup actions, or we're elevated. In that case, go for it.
return false;
@@ -1103,7 +1102,7 @@ namespace winrt::TerminalApp::implementation
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
const auto dispatchToElevatedWindow = ctrlPressed && !IsElevated();
const auto dispatchToElevatedWindow = ctrlPressed && !IsRunningElevated();
if ((shiftPressed || dispatchToElevatedWindow) && !debugTap)
{
@@ -2869,7 +2868,7 @@ namespace winrt::TerminalApp::implementation
// want to create an animation.
WUX::Media::Animation::Timeline::AllowDependentAnimations(!_settings.GlobalSettings().DisableAnimations());
_tabRow.ShowElevationShield(IsElevated() && _settings.GlobalSettings().ShowAdminShield());
_tabRow.ShowElevationShield(IsRunningElevated() && _settings.GlobalSettings().ShowAdminShield());
Media::SolidColorBrush transparent{ Windows::UI::Colors::Transparent() };
_tabView.Background(transparent);
@@ -3956,7 +3955,7 @@ namespace winrt::TerminalApp::implementation
{
// Try to handle auto-elevation
const auto requestedElevation = controlSettings.DefaultSettings().Elevate();
const auto currentlyElevated = IsElevated();
const auto currentlyElevated = IsRunningElevated();
// We aren't elevated, but we want to be.
if (requestedElevation && !currentlyElevated)

View File

@@ -126,7 +126,8 @@ namespace winrt::TerminalApp::implementation
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
bool IsElevated() const noexcept;
bool CanDragDrop() const noexcept;
bool IsRunningElevated() const noexcept;
void OpenSettingsUI();
void WindowActivated(const bool activated);

View File

@@ -202,35 +202,6 @@ namespace winrt::TerminalApp::implementation
return isUwp;
}
// Method Description:
// - Called around the codebase to discover if Terminal is running elevated
// Arguments:
// - <none> - reports internal state
// Return Value:
// - True if elevated, false otherwise.
bool TerminalWindow::IsElevated() const noexcept
{
// use C++11 magic statics to make sure we only do this once.
// This won't change over the lifetime of the application
static const auto isElevated = []() {
// *** THIS IS A SINGLETON ***
auto result = false;
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
try
{
result = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsElevated();
}
CATCH_LOG();
return result;
}();
return isElevated;
}
// Method Description:
// - Build the UI for the terminal app. Before this method is called, it
// should not be assumed that the TerminalApp is usable. The Settings

View File

@@ -66,7 +66,6 @@ namespace winrt::TerminalApp::implementation
void Create();
bool IsUwp() const noexcept;
bool IsElevated() const noexcept;
void Quit();

View File

@@ -51,8 +51,6 @@ namespace TerminalApp
// registered?" when it definitely is.
void Create();
Boolean IsElevated();
Boolean HasCommandlineArguments();
Int32 SetStartupCommandline(String[] commands);

View File

@@ -177,7 +177,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// from state.json. We'll then load the Local props from
// `elevated-state.json`
// - If we're unelevated, then load _everything_ from state.json.
if (::Microsoft::Console::Utils::IsElevated())
if (::Microsoft::Console::Utils::IsRunningElevated())
{
// Only load shared properties if we're elevated
FromJson(root, FileSource::Shared);
@@ -225,7 +225,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
//
// After that's done, we'll write our Local properties into
// elevated-state.json.
if (::Microsoft::Console::Utils::IsElevated())
if (::Microsoft::Console::Utils::IsRunningElevated())
{
std::string errs;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder{}.newCharReader() };
@@ -353,7 +353,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// permissions, so we don't potentially read malicious data.
std::optional<std::string> ApplicationState::_readLocalContents() const
{
return ::Microsoft::Console::Utils::IsElevated() ?
return ::Microsoft::Console::Utils::IsRunningElevated() ?
ReadUTF8FileIfExists(_elevatedPath, true) :
ReadUTF8FileIfExists(_sharedPath, false);
}
@@ -374,7 +374,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// will atomically write to `user-state.json`
void ApplicationState::_writeLocalContents(const std::string_view content) const
{
if (::Microsoft::Console::Utils::IsElevated())
if (::Microsoft::Console::Utils::IsRunningElevated())
{
// DON'T use WriteUTF8FileAtomic, which will write to a temporary file
// then rename that file to the final filename. That actually lets us

View File

@@ -50,6 +50,7 @@ private:
std::vector<winrt::Microsoft::Terminal::Settings::Model::GlobalSummonArgs> _hotkeys;
std::unique_ptr<NotificationIcon> _notificationIcon;
bool _quitting{ false };
void _windowStartedHandler(const std::shared_ptr<WindowThread>& sender);

View File

@@ -25,7 +25,7 @@
<AdditionalOptions>%(AdditionalOptions) /defaultlib:ucrtd.lib</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and '$(Configuration)'=='Release'">
<ItemDefinitionGroup Condition="'$(EnableHybridCRT)'=='true' and ('$(Configuration)'=='Release' or '$(Configuration)'=='AuditMode')">
<ClCompile>
<!-- We use MultiThreaded, rather than MultiThreadedDLL, to avoid DLL dependencies on VCRUNTIME140.dll and MSVCP140.dll. -->
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>

View File

@@ -81,12 +81,26 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup>
<!--
We don't need to use HybridCRT for Fuzzing, so just skip it entirely.
Fuzzing requires the address sanitizer runtime library plus the fuzzing
harness. They're probably not compatible.
Audit, however, *does* require linking components built in Release mode...
-->
<ConfigurationSupportsHybridCRT Condition="'$(Configuration)'=='Fuzzing'">false</ConfigurationSupportsHybridCRT>
<ConfigurationSupportsHybridCRT Condition="'$(ConfigurationSupportsHybridCRT)'==''">true</ConfigurationSupportsHybridCRT>
</PropertyGroup>
<!-- For ALL build types-->
<PropertyGroup Label="Configuration">
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<LinkIncremental>false</LinkIncremental>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
<EnableHybridCRT Condition="'$(EnableHybridCRT)'=='' and '$(ConfigurationSupportsHybridCRT)'=='true'">true</EnableHybridCRT>
<UseCrtSDKReferenceStaticWarning Condition="'$(EnableHybridCRT)'=='true'">false</UseCrtSDKReferenceStaticWarning>
</PropertyGroup>
<ItemDefinitionGroup>

View File

@@ -20,7 +20,7 @@ bool INPUT_READ_HANDLE_DATA::IsInputPending() const
bool INPUT_READ_HANDLE_DATA::IsMultilineInput() const
{
FAIL_FAST_IF(!_isInputPending); // we shouldn't have multiline input without a pending input.
assert(_isInputPending); // we shouldn't have multiline input without a pending input.
return _isMultilineInput;
}

View File

@@ -1019,27 +1019,43 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline
}
Tracing::s_TraceCookedRead(_clientProcess, _backupLimit, base::saturated_cast<ULONG>(idx));
ProcessAliases(LineCount);
// Don't be fooled by ProcessAliases only taking one argument. It rewrites multiple
// class members on return, including `_bytesRead`, requiring us to reconstruct `input`.
ProcessAliases(LineCount);
input = { _backupLimit, _bytesRead / sizeof(wchar_t) };
// The exact reasons for this are unclear to me (the one writing this comment), but this code used to
// split the contents of a multiline alias (for instance `doskey test=echo foo$Techo bar$Techo baz`)
// into multiple separate read outputs, ensuring that the client receives them line by line.
//
// This code first truncates the `input` to only contain the first line, so that Consume() below only
// writes that line into the user buffer. We'll later store the remainder in SaveMultilinePendingInput().
if (LineCount > 1)
{
input = input.substr(0, idx + 1);
// ProcessAliases() is supposed to end each line with \r\n. If it doesn't we might as well fail-fast.
const auto firstLineEnd = input.find(UNICODE_LINEFEED) + 1;
input = input.substr(0, std::min(input.size(), firstLineEnd));
}
}
}
const auto inputSizeBefore = input.size();
GetInputBuffer()->Consume(isUnicode, input, writer);
if (!input.empty())
if (LineCount > 1)
{
if (LineCount > 1)
{
GetInputReadHandleData()->SaveMultilinePendingInput(input);
}
else
{
GetInputReadHandleData()->SavePendingInput(input);
}
// This is a continuation of the above identical if condition.
// We've truncated the `input` slice and now we need to restore it.
const auto inputSizeAfter = input.size();
const auto amountConsumed = inputSizeBefore - inputSizeAfter;
input = { _backupLimit, _bytesRead / sizeof(wchar_t) };
input = input.substr(std::min(input.size(), amountConsumed));
GetInputReadHandleData()->SaveMultilinePendingInput(input);
}
else if (!input.empty())
{
GetInputReadHandleData()->SavePendingInput(input);
}
numBytes = _userBufferSize - writer.size();

View File

@@ -288,28 +288,36 @@ try
{
bytesRead = 0;
auto pending = readHandleState.GetPendingInput();
const auto pending = readHandleState.GetPendingInput();
auto input = pending;
// This is basically the continuation of COOKED_READ_DATA::_handlePostCharInputLoop.
if (readHandleState.IsMultilineInput())
{
const auto idx = pending.find(UNICODE_LINEFEED);
if (idx != decltype(pending)::npos)
{
// +1 to include the newline.
pending = pending.substr(0, idx + 1);
}
const auto firstLineEnd = input.find(UNICODE_LINEFEED) + 1;
input = input.substr(0, std::min(input.size(), firstLineEnd));
}
const auto inputSizeBefore = input.size();
std::span writer{ buffer };
inputBuffer.Consume(unicode, pending, writer);
inputBuffer.Consume(unicode, input, writer);
if (pending.empty())
// Since we truncated `input` to only include the first line,
// we need to restore `input` here to the entirety of the remaining input.
if (readHandleState.IsMultilineInput())
{
const auto inputSizeAfter = input.size();
const auto amountConsumed = inputSizeBefore - inputSizeAfter;
input = pending.substr(std::min(pending.size(), amountConsumed));
}
if (input.empty())
{
readHandleState.CompletePending();
}
else
{
readHandleState.UpdatePending(pending);
readHandleState.UpdatePending(input);
}
bytesRead = buffer.size() - writer.size();

View File

@@ -96,7 +96,8 @@ namespace Microsoft::Console::Utils
GUID CreateV5Uuid(const GUID& namespaceGuid, const std::span<const std::byte> name);
bool IsElevated();
bool CanUwpDragDrop();
bool IsRunningElevated();
// This function is only ever used by the ConPTY connection in
// TerminalConnection. However, that library does not have a good system of

View File

@@ -653,9 +653,18 @@ GUID Utils::CreateV5Uuid(const GUID& namespaceGuid, const std::span<const std::b
return EndianSwap(newGuid);
}
bool Utils::IsElevated()
// * Elevated users cannot use the modern drag drop experience. This is
// specifically normal users running the Terminal as admin
// * The Default Administrator, who does not have a split token, CAN drag drop
// perfectly fine. So in that case, we want to return false.
// * This has to be kept separate from IsRunningElevated, which is exclusively
// used for "is this instance running as admin".
bool Utils::CanUwpDragDrop()
{
static auto isElevated = []() {
// There's a lot of wacky double negatives here so that the logic is
// basically the same as IsRunningElevated, but the end result semantically
// makes sense as "CanDragDrop".
static auto isDragDropBroken = []() {
try
{
wil::unique_handle processToken{ GetCurrentProcessToken() };
@@ -670,8 +679,30 @@ bool Utils::IsElevated()
//
// See GH#7754, GH#11096
return false;
// drag drop is _not_ broken -> they _can_ drag drop
}
// If they are running admin, they cannot drag drop.
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// This failed? That's very peculiar indeed. Let's err on the side
// of "drag drop is broken", just in case.
return true;
}
}();
return !isDragDropBroken;
}
// See CanUwpDragDrop, GH#13928 for why this is different.
bool Utils::IsRunningElevated()
{
static auto isElevated = []() {
try
{
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
}
catch (...)