Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f11bfff784 | ||
|
|
78aea46fb3 | ||
|
|
1549a89dc3 | ||
|
|
47382cdd86 |
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
project(KSwitcher VERSION 0.6.87 LANGUAGES CXX RC)
|
||||
project(KSwitcher VERSION 0.6.88 LANGUAGES CXX RC)
|
||||
if(NOT WIN32)
|
||||
message(FATAL_ERROR "KSwitcher uses native Windows APIs")
|
||||
endif()
|
||||
|
||||
@@ -43,6 +43,8 @@ Far Manager є зразком для оформлення файлового м
|
||||
- Ctrl+F вставляє повний шлях елемента під курсором активної панелі в позицію
|
||||
курсора командного рядка або замінює виділення. Подвійні лапки додаються
|
||||
лише до шляхів із пробілами. Для `..` вставляється шлях батьківської папки.
|
||||
- Ctrl+Enter вставляє лише назву файла або папки під курсором активної панелі
|
||||
за тими ж правилами вставлення й лапок. Рядок `..` пропускається.
|
||||
- Ctrl+C копіює весь введений у командний рядок текст, навіть коли виділено
|
||||
лише його частину.
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,12 @@
|
||||
# Latest Windows release
|
||||
|
||||
## v0.6.88 — 2026-11-16
|
||||
|
||||
In Files, Ctrl+Enter inserts the name of the file or folder under the active pane cursor into the command line. An open Files window can still request the LAN peer list after KSwitcher updates and restarts.
|
||||
|
||||
**Українською.** У Files Ctrl+Enter вставляє в командний рядок назву файла або папки під курсором активної панелі. Відкрите вікно Files і далі може отримувати список LAN-комп’ютерів після оновлення та автоматичного перезапуску KSwitcher.
|
||||
|
||||
|
||||
## v0.6.87 — 2026-11-15
|
||||
|
||||
Remote PowerShell in Files now displays errors as text and hides progress metadata. Update the PC that runs the commands to remove raw CLIXML from terminal output. This release supersedes v0.6.86.
|
||||
|
||||
@@ -1 +1 @@
|
||||
8e69019173d92de7790917573c9e95bb96104994d518170cad320d294fca2153 KSwitcher-win-x64.zip
|
||||
d48e590580801a39a08ac8f5192983610e0a3fec9e5b0cf7f01a40a063cbed78 KSwitcher-win-x64.zip
|
||||
+59
-59
@@ -1,136 +1,136 @@
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"size": 2462208,
|
||||
"sha256": "fad74ffb05e9c3ce6ada562c610837539809682cef33d0be1e878dc45e4dea9d",
|
||||
"path": "KSwitcher.exe"
|
||||
"path": "KSwitcher.exe",
|
||||
"sha256": "aa542387388904d2a8df98bdef0e0b25b12aa294ded279f3308553d762086fee",
|
||||
"size": 5852660
|
||||
},
|
||||
{
|
||||
"size": 2439168,
|
||||
"sha256": "8c88bd7f4018d0f400e56f2ae21c63b259f2ab482adfd82bf2e067a48e7eb47a",
|
||||
"path": "KSwitcher.Config.exe"
|
||||
"path": "KSwitcher.Config.exe",
|
||||
"sha256": "c128e8affc7485ba475228ca9bee6915948208405bd84110ffc776ebf8a3d0da",
|
||||
"size": 5917446
|
||||
},
|
||||
{
|
||||
"size": 3050496,
|
||||
"sha256": "7d2a3d04436989411e1220569fbfef95a9916696ec97b62963c3c04f128a11ed",
|
||||
"path": "KSwitcher.Screenshot.exe"
|
||||
"path": "KSwitcher.Screenshot.exe",
|
||||
"sha256": "82397c1e4d73415449ba7389a716d6e1ec4dab2310b1471369f467435b771762",
|
||||
"size": 5747437
|
||||
},
|
||||
{
|
||||
"size": 3660288,
|
||||
"sha256": "7a5596ee03cce3000f83f13d8de1113be467590abcf03ef4a2bd8d13f1d3b5fe",
|
||||
"path": "KSwitcher.Files.exe"
|
||||
"path": "KSwitcher.Files.exe",
|
||||
"sha256": "c86b7ff32468bafa6f658a810f475b557f47a23ba42a1739db09d7eeab6fb533",
|
||||
"size": 8159101
|
||||
},
|
||||
{
|
||||
"size": 194912,
|
||||
"path": "WebView2Loader.dll",
|
||||
"sha256": "d3fce90bdeecb08596e377dea6a316354dd8949e32ff09b89d51be00c14e21b6",
|
||||
"path": "WebView2Loader.dll"
|
||||
"size": 194912
|
||||
},
|
||||
{
|
||||
"size": 1103,
|
||||
"path": "terminal/addon-fit-LICENSE.txt",
|
||||
"sha256": "e256f01188af527e4d06d21d06fbf785ae9c50d4b328bf03cbe0ba7f0aa4228f",
|
||||
"path": "terminal/addon-fit-LICENSE.txt"
|
||||
"size": 1103
|
||||
},
|
||||
{
|
||||
"size": 1521,
|
||||
"path": "terminal/addon-fit.js",
|
||||
"sha256": "ba3ea256ce0620a0992a197d6c9baea64823fc93d8da07a9e366ca9943c18527",
|
||||
"path": "terminal/addon-fit.js"
|
||||
"size": 1521
|
||||
},
|
||||
{
|
||||
"size": 527,
|
||||
"path": "terminal/index.html",
|
||||
"sha256": "084d97a727b778fb10d31adcd557ee7840a38377ed60e0ef0f3ece93b349b1ef",
|
||||
"path": "terminal/index.html"
|
||||
"size": 527
|
||||
},
|
||||
{
|
||||
"size": 4167,
|
||||
"sha256": "d60e6ff8948b6616695297695b05ef6e74b497a8e32e6031fc2e4fe2cca39ca7",
|
||||
"path": "terminal/terminal.js"
|
||||
"path": "terminal/terminal.js",
|
||||
"sha256": "fb302b2902fea6a815a8266811f350d1e4c108ca88fafd49e6eddcbfff90a5e5",
|
||||
"size": 4268
|
||||
},
|
||||
{
|
||||
"size": 1261,
|
||||
"path": "terminal/xterm-LICENSE.txt",
|
||||
"sha256": "b569f629d00f2626a8100df2a1798210535621e42164dfd426a6fe5aac7b0ccd",
|
||||
"path": "terminal/xterm-LICENSE.txt"
|
||||
"size": 1261
|
||||
},
|
||||
{
|
||||
"size": 7112,
|
||||
"path": "terminal/xterm.css",
|
||||
"sha256": "854a7c0fb70e8b1a083c16797ab827299fb18744f5ad34f227b48337e33293c6",
|
||||
"path": "terminal/xterm.css"
|
||||
"size": 7112
|
||||
},
|
||||
{
|
||||
"size": 488663,
|
||||
"path": "terminal/xterm.js",
|
||||
"sha256": "14903579ff54664cd72f8e8699e6961a6272c21863ec1c3b118cdc8af5d4a972",
|
||||
"path": "terminal/xterm.js"
|
||||
"size": 488663
|
||||
},
|
||||
{
|
||||
"size": 4401,
|
||||
"path": "LICENSE",
|
||||
"sha256": "d3c81140cce01c26bf6cbf52aa40e0825e1fa35b9a91d1387170a65d2597082c",
|
||||
"path": "LICENSE"
|
||||
"size": 4401
|
||||
},
|
||||
{
|
||||
"size": 1075,
|
||||
"path": "json-LICENSE.txt",
|
||||
"sha256": "c0d068392ea65358b798b8c165103560f06e9e3b38c4ab4e2d8810a7b931af86",
|
||||
"path": "json-LICENSE.txt"
|
||||
"size": 1075
|
||||
},
|
||||
{
|
||||
"size": 883,
|
||||
"path": "files-text-license.txt",
|
||||
"sha256": "185c5a37521316e940ead89cbf0b1ba5862d810c7c966e6c6a14a4a515b23625",
|
||||
"path": "files-text-license.txt"
|
||||
"size": 883
|
||||
},
|
||||
{
|
||||
"size": 94223,
|
||||
"path": "README.md",
|
||||
"sha256": "7b34f2af7341f57d7bac1b5b7e55a40595a6bc20f461f98c0c6320336d0deba7",
|
||||
"path": "README.md"
|
||||
"size": 94223
|
||||
},
|
||||
{
|
||||
"size": 11418,
|
||||
"path": "LAN-PREVIEW.md",
|
||||
"sha256": "2c13d3ed4761e679c352fb1ade24a1ec3060ad2862376ede801cdee5fcc3bada",
|
||||
"path": "LAN-PREVIEW.md"
|
||||
"size": 11418
|
||||
},
|
||||
{
|
||||
"size": 682867,
|
||||
"path": "dictionaries/en.txt",
|
||||
"sha256": "5f267c141c3d6837870e1c098f86b89a113ba300343119432644ead88f720c21",
|
||||
"path": "dictionaries/en.txt"
|
||||
"size": 682867
|
||||
},
|
||||
{
|
||||
"size": 20138,
|
||||
"path": "dictionaries/LICENSE-CC-BY-SA-4.0.txt",
|
||||
"sha256": "28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5",
|
||||
"path": "dictionaries/LICENSE-CC-BY-SA-4.0.txt"
|
||||
"size": 20138
|
||||
},
|
||||
{
|
||||
"size": 2265,
|
||||
"path": "dictionaries/README.md",
|
||||
"sha256": "3017bf44d3be9d9dfab21bd6778aa52b7947e61acf9ce2bc86b41d6e949ac311",
|
||||
"path": "dictionaries/README.md"
|
||||
"size": 2265
|
||||
},
|
||||
{
|
||||
"size": 1060364,
|
||||
"path": "dictionaries/ru.txt",
|
||||
"sha256": "9ef922c7699569304a428f6aba0fd13a21341c0d0cb9561f37ef83c41577a28b",
|
||||
"path": "dictionaries/ru.txt"
|
||||
"size": 1060364
|
||||
},
|
||||
{
|
||||
"size": 1280,
|
||||
"path": "dictionaries/sources.json",
|
||||
"sha256": "98e5b3fe7304e37705c9e5ff48b0b399ccb16e806736d21f09921b99e5f2a408",
|
||||
"path": "dictionaries/sources.json"
|
||||
"size": 1280
|
||||
},
|
||||
{
|
||||
"size": 940799,
|
||||
"path": "dictionaries/uk.txt",
|
||||
"sha256": "d30e990d6ec2983c04f3644a3c61c6c668e8c542323f5931916fdd55b916eebf",
|
||||
"path": "dictionaries/uk.txt"
|
||||
"size": 940799
|
||||
},
|
||||
{
|
||||
"size": 993,
|
||||
"path": "tools/README.txt",
|
||||
"sha256": "a34b5161a8315af037e1ec71d816bfc688f7c364141d4ee2347cf0515ef0c82a",
|
||||
"path": "tools/README.txt"
|
||||
"size": 993
|
||||
},
|
||||
{
|
||||
"size": 133120,
|
||||
"sha256": "759c4ad30bbcf1f99d086dbd88dd2f5c68012d6a793479e8712a6934e17e23f4",
|
||||
"path": "tools/StayHere.exe"
|
||||
"path": "tools/StayHere.exe",
|
||||
"sha256": "bb595202cc4749f3c0fe47adc92d4b02a174abeb5765e493673de9f5e070251c",
|
||||
"size": 540583
|
||||
},
|
||||
{
|
||||
"size": 2796,
|
||||
"path": "tools/StayHere-README.md",
|
||||
"sha256": "ba214e2aca7405e698b3ab21ceb1f41ce088edd996b3e30e4a9d58ff496f9413",
|
||||
"path": "tools/StayHere-README.md"
|
||||
"size": 2796
|
||||
}
|
||||
],
|
||||
"version": "0.6.87",
|
||||
"version": "0.6.88",
|
||||
"schema": 1
|
||||
}
|
||||
+3
-3
@@ -9,8 +9,8 @@ IDC_SCREENSHOT_PENCIL CURSOR "icons/lucide/pencil.cur"
|
||||
1 RT_MANIFEST "app.manifest"
|
||||
201 RCDATA "update.ps1"
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,6,87,0
|
||||
PRODUCTVERSION 0,6,87,0
|
||||
FILEVERSION 0,6,88,0
|
||||
PRODUCTVERSION 0,6,88,0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
BEGIN
|
||||
@@ -20,7 +20,7 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "FileDescription", "KSwitcher — native keyboard and clipboard utility"
|
||||
VALUE "ProductName", "KSwitcher"
|
||||
VALUE "FileVersion", "0.6.87"
|
||||
VALUE "FileVersion", "0.6.88"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -58,6 +58,9 @@ terminal.attachCustomKeyEventHandler(event => {
|
||||
else if (event.code === 'KeyF' || event.code === 'KeyC') {
|
||||
if (!event.repeat) bridge.postMessage(event.code === 'KeyF' ? 'insert-path' : 'copy-command-line');
|
||||
}
|
||||
else if (event.key === 'Enter') {
|
||||
if (!event.repeat) bridge.postMessage('insert-name');
|
||||
}
|
||||
else return true;
|
||||
event.preventDefault();
|
||||
return false;
|
||||
|
||||
+16
-5
@@ -4,17 +4,25 @@
|
||||
#include <cstring>
|
||||
namespace ks
|
||||
{
|
||||
bool configurationPeer(HWND window, const wchar_t *filename)
|
||||
namespace
|
||||
{
|
||||
std::filesystem::path processImage(HWND window)
|
||||
{
|
||||
DWORD pid{};
|
||||
GetWindowThreadProcessId(window, &pid);
|
||||
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
||||
if (!process) return false;
|
||||
if (!process) return {};
|
||||
wchar_t path[32768]; DWORD count = std::size(path);
|
||||
bool ok = QueryFullProcessImageNameW(process, 0, path, &count) != 0;
|
||||
CloseHandle(process);
|
||||
auto expected = std::filesystem::path(executable()).parent_path() / filename;
|
||||
return ok && _wcsicmp(path, expected.c_str()) == 0;
|
||||
return ok ? std::filesystem::path(path) : std::filesystem::path{};
|
||||
}
|
||||
}
|
||||
|
||||
bool configurationPeer(HWND window, const wchar_t *filename)
|
||||
{
|
||||
const auto expected = std::filesystem::path(executable()).parent_path() / filename;
|
||||
return _wcsicmp(processImage(window).c_str(), expected.c_str()) == 0;
|
||||
}
|
||||
void launchConfiguration(App &app, bool snippets, bool logs)
|
||||
{
|
||||
@@ -35,7 +43,10 @@ void launchConfiguration(App &app, bool snippets, bool logs)
|
||||
LRESULT configurationRequest(App &app, HWND sender, const COPYDATASTRUCT &message)
|
||||
{
|
||||
const bool filesPeers = message.dwData == FilesLanPeers;
|
||||
if (!configurationPeer(sender, filesPeers ? L"KSwitcher.Files.exe" : L"KSwitcher.Config.exe") || message.cbData > ConfigLimit ||
|
||||
const bool knownSender = filesPeers
|
||||
? isFilesPeerImage(processImage(sender), std::filesystem::path(executable()).parent_path())
|
||||
: configurationPeer(sender, L"KSwitcher.Config.exe");
|
||||
if (!knownSender || message.cbData > ConfigLimit ||
|
||||
(message.cbData && !message.lpData)) return FALSE;
|
||||
Bytes reply;
|
||||
bool ok = false;
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
|
||||
inline constexpr ULONG_PTR FilesLanPeers = 0x4b53010d;
|
||||
inline constexpr ULONG_PTR FilesLanPeersReply = 0x4b53010e;
|
||||
inline constexpr DWORD FilesLanPeersLimit = 64 * 1024;
|
||||
|
||||
namespace ks
|
||||
{
|
||||
inline bool isFilesPeerImage(const std::filesystem::path &image, const std::filesystem::path &install)
|
||||
{
|
||||
if (_wcsicmp(image.filename().c_str(), L"KSwitcher.Files.exe") != 0) return false;
|
||||
const auto directory = image.parent_path();
|
||||
if (_wcsicmp(directory.c_str(), install.c_str()) == 0) return true;
|
||||
|
||||
// Updating moves a still-running Files executable into the transaction backup.
|
||||
// Windows then reports the moved path for its process image.
|
||||
if (_wcsicmp(directory.filename().c_str(), L"backup") != 0) return false;
|
||||
const auto transaction = directory.parent_path();
|
||||
if (_wcsicmp(transaction.parent_path().c_str(), install.c_str()) != 0) return false;
|
||||
constexpr std::wstring_view prefix = L".kswitcher-update-";
|
||||
const auto name = transaction.filename().wstring();
|
||||
if (name.size() != prefix.size() + 32 || _wcsnicmp(name.c_str(), prefix.data(), prefix.size()) != 0)
|
||||
return false;
|
||||
return std::wstring_view(name).substr(prefix.size()).find_first_not_of(L"0123456789abcdefABCDEF")
|
||||
== std::wstring_view::npos;
|
||||
}
|
||||
}
|
||||
+7
-3
@@ -909,12 +909,14 @@ std::wstring powerShellPath(const fs::path &path)
|
||||
return quoted+L"'";
|
||||
}
|
||||
|
||||
void insertCurrentPanelPath()
|
||||
void insertCurrentPanelPath(bool nameOnly = false)
|
||||
{
|
||||
const auto &panel=panels[active];
|
||||
const auto row=currentPanelRow(panel);
|
||||
if(row==LB_ERR) return;
|
||||
const auto &path=panel.rows[row].native();
|
||||
const auto &item=panel.rows[row];
|
||||
if(nameOnly && row==0 && panel.directory.has_relative_path()) return;
|
||||
const auto path=nameOnly?item.filename().native():item.native();
|
||||
std::wstring quoted;
|
||||
if(path.find(L' ')!=std::wstring::npos)
|
||||
{
|
||||
@@ -974,6 +976,7 @@ bool ensureTerminalView(HWND owner)
|
||||
if(GetForegroundWindow()==owner) SetFocus(terminalInput);
|
||||
}
|
||||
else if(message==L"insert-path") insertCurrentPanelPath();
|
||||
else if(message==L"insert-name") insertCurrentPanelPath(true);
|
||||
else if(message==L"copy-command-line") SendMessageW(terminalInput,WM_COPY,0,0);
|
||||
else if(message==L"toggle") showTerminal(owner,!terminalVisible);
|
||||
else if(!terminalVisible && (message==L"grow" || message==L"shrink"))
|
||||
@@ -5147,11 +5150,12 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE, PWSTR, int show)
|
||||
{
|
||||
const bool ctrl=(GetKeyState(VK_CONTROL)&0x8000)!=0;
|
||||
const bool shift=(GetKeyState(VK_SHIFT)&0x8000)!=0;
|
||||
if(ctrl && !shift && (message.wParam=='F' || message.wParam=='C'))
|
||||
if(ctrl && !shift && (message.wParam=='F' || message.wParam=='C' || message.wParam==VK_RETURN))
|
||||
{
|
||||
if(!(message.lParam & (1LL<<30)))
|
||||
{
|
||||
if(message.wParam=='F') insertCurrentPanelPath();
|
||||
else if(message.wParam==VK_RETURN) insertCurrentPanelPath(true);
|
||||
else SendMessageW(terminalInput,WM_COPY,0,0);
|
||||
}
|
||||
continue;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#include "platform.h"
|
||||
namespace ks
|
||||
{
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.87";
|
||||
inline constexpr wchar_t AppVersion[] = L"0.6.88";
|
||||
inline constexpr UINT UpdateMessage = WM_APP + 7;
|
||||
inline constexpr UINT UpdateCheckIntervalMs = 6 * 60 * 60 * 1000;
|
||||
inline constexpr UINT UpdateNotificationRetryMs = 5 * 60 * 1000;
|
||||
|
||||
@@ -20,6 +20,9 @@ public static class FilesActivationUi {
|
||||
[DllImport("user32.dll")] public static extern IntPtr GetDlgItem(IntPtr window, int id);
|
||||
[DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr after, string type, string title);
|
||||
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr window);
|
||||
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
||||
[DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr window);
|
||||
[DllImport("user32.dll")] static extern void keybd_event(byte key, byte scan, uint flags, UIntPtr extra);
|
||||
[DllImport("user32.dll")] public static extern bool PostMessage(IntPtr window, uint msg, IntPtr w, IntPtr l);
|
||||
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr window, IntPtr process);
|
||||
[DllImport("user32.dll")] static extern bool GetGUIThreadInfo(uint thread, ref GuiInfo info);
|
||||
@@ -36,6 +39,14 @@ public static class FilesActivationUi {
|
||||
return info.Focus;
|
||||
}
|
||||
|
||||
public static bool Activate(IntPtr window) {
|
||||
if (GetForegroundWindow() == window) return true;
|
||||
keybd_event(0x12, 0, 0, UIntPtr.Zero);
|
||||
keybd_event(0x12, 0, 2, UIntPtr.Zero);
|
||||
SetForegroundWindow(window);
|
||||
return GetForegroundWindow() == window;
|
||||
}
|
||||
|
||||
public static void ClickRow(IntPtr list, int row, bool doubleClick) {
|
||||
Rect rect;
|
||||
if (SendRect(list, 0x198, new IntPtr(row), out rect).ToInt32() == -1)
|
||||
@@ -179,6 +190,21 @@ try {
|
||||
[FilesActivationUi]::Send($left, 0x188, [IntPtr]::Zero, [IntPtr]::Zero).ToInt32() -eq (Find-Row $left '..')
|
||||
}
|
||||
if ((Read-Text $inputBox) -cne 'draft command') { throw 'Pane navigation changed the command line.' }
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$fileName = [IO.Path]::GetFileName($document)
|
||||
foreach ($name in $fileName, 'Test folder') {
|
||||
$label = if ($name -eq $fileName) { $name } else { "[$name]" }
|
||||
Select-Row $right $label
|
||||
[void][FilesActivationUi]::Write($inputBox, 0x0C, [IntPtr]::Zero, 'draft command')
|
||||
[void][FilesActivationUi]::Send($inputBox, 0xB1, [IntPtr]6, [IntPtr]13)
|
||||
Wait-Until 'Files activation for Ctrl+Enter' {
|
||||
[FilesActivationUi]::Activate($window) -and
|
||||
[FilesActivationUi]::Focus($window) -eq $inputBox
|
||||
}
|
||||
$shell.SendKeys('^{ENTER}')
|
||||
$expected = 'draft "{0}"' -f $name
|
||||
Wait-Until "Ctrl+Enter inserting $name" { (Read-Text $inputBox) -ceq $expected }
|
||||
}
|
||||
[void][FilesActivationUi]::Write($inputBox, 0x0C, [IntPtr]::Zero, '')
|
||||
Write-Output 'Tab and Down navigated the panes while preserving command-line focus and text.'
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <winsock2.h>
|
||||
#include <sddl.h>
|
||||
#include "lan_files.h"
|
||||
#include "files_lan_ipc.h"
|
||||
#include <bit>
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
@@ -18,6 +19,23 @@ void require(bool condition,const char *message)
|
||||
if(!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
void verifyFilesPeerImage()
|
||||
{
|
||||
const fs::path install = LR"(C:\Tools\KSwitcher)";
|
||||
const auto transaction = install / L".kswitcher-update-0123456789abcdef0123456789abcdef";
|
||||
constexpr auto files = L"KSwitcher.Files.exe";
|
||||
require(isFilesPeerImage(install / files, install), "installed Files can request LAN peers");
|
||||
require(isFilesPeerImage(transaction / L"backup" / files, install),
|
||||
"Files open during an update can still request LAN peers");
|
||||
require(!isFilesPeerImage(transaction / L"stage" / files, install), "staged Files image is rejected");
|
||||
require(!isFilesPeerImage(transaction / L"backup" / L"KSwitcher.Config.exe", install),
|
||||
"another executable in the backup is rejected");
|
||||
require(!isFilesPeerImage(install / L".kswitcher-update-invalid" / L"backup" / files, install),
|
||||
"malformed transaction directory is rejected");
|
||||
require(!isFilesPeerImage(install.parent_path() / transaction.filename() / L"backup" / files, install),
|
||||
"backup outside the active installation is rejected");
|
||||
}
|
||||
|
||||
void save(const fs::path &path,const std::string &text)
|
||||
{
|
||||
std::ofstream file(path,std::ios::binary|std::ios::trunc);
|
||||
@@ -111,6 +129,7 @@ int main()
|
||||
int result=0;
|
||||
try
|
||||
{
|
||||
verifyFilesPeerImage();
|
||||
fs::create_directory(root);
|
||||
const auto client=randomHex(16),first=randomHex(16),second=randomHex(16),key=randomHex(32);
|
||||
auto lookup=[&](const std::string &id){return id==client?key:std::string{};};
|
||||
|
||||
Reference in new issue
Block a user