KiCad PCB EDA Suite
Loading...
Searching...
No Matches
windows/environment.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020 Ian McInerney <Ian.S.McInerney at ieee.org>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
22#include <wx/intl.h>
23#include <wx/filename.h>
24#include <wx/stdpaths.h>
25#include <wx/string.h>
26#include <wx/tokenzr.h>
27#include <wx/app.h>
28#include <wx/uri.h>
29
30#include <Windows.h>
31#include <shellapi.h>
32#include <shlwapi.h>
33#if defined( __MINGW32__ )
34 #include <shobjidl.h>
35#else
36 #include <shobjidl_core.h>
37#endif
38#include <winhttp.h>
39
40#include <Softpub.h>
41#include <wincrypt.h>
42#include <wintrust.h>
43
44#define INCLUDE_KICAD_VERSION // fight me
45#include <kicad_build_version.h>
46
47
49{
50 ::SetCurrentProcessExplicitAppUserModelID( GetAppUserModelId().wc_str() );
51}
52
53
54bool KIPLATFORM::ENV::MoveToTrash( const wxString& aPath, wxString& aError )
55{
56 // The filename field must be a double-null terminated string
57 wxString temp = aPath + '\0';
58
59 SHFILEOPSTRUCT fileOp;
60 ::ZeroMemory( &fileOp, sizeof( fileOp ) );
61
62 fileOp.hwnd = nullptr; // Set to null since there is no progress dialog
63 fileOp.wFunc = FO_DELETE;
64 fileOp.pFrom = temp.c_str();
65 fileOp.pTo = nullptr; // Set to to NULL since we aren't moving the file
66 fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT;
67
68 int eVal = SHFileOperation( &fileOp );
69
70 if( eVal != 0 )
71 {
72 aError = wxString::Format( _( "Error code: %d" ), eVal );
73 return false;
74 }
75
76 return true;
77}
78
79
80bool KIPLATFORM::ENV::IsNetworkPath( const wxString& aPath )
81{
82 return ::PathIsNetworkPathW( aPath.wc_str() );
83}
84
85
87{
88 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
89 // complains about not existing app. so use a dummy app
90 if( wxTheApp == nullptr )
91 {
92 wxApp dummy;
93 return wxStandardPaths::Get().GetDocumentsDir();
94 }
95
96 return wxStandardPaths::Get().GetDocumentsDir();
97}
98
99
101{
102 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
103 // complains about not existing app. so use a dummy app
104 if( wxTheApp == nullptr )
105 {
106 wxApp dummy;
107 return wxStandardPaths::Get().GetUserConfigDir();
108 }
109
110 return wxStandardPaths::Get().GetUserConfigDir();
111}
112
113
115{
116 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
117 // complains about not existing app. so use a dummy app
118 if( wxTheApp == nullptr )
119 {
120 wxApp dummy;
121 return wxStandardPaths::Get().GetUserDataDir();
122 }
123
124 return wxStandardPaths::Get().GetUserDataDir();
125}
126
127
129{
130 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
131 // complains about not existing app. so use a dummy app
132 if( wxTheApp == nullptr )
133 {
134 wxApp dummy;
135 return wxStandardPaths::Get().GetUserLocalDataDir();
136 }
137
138 return wxStandardPaths::Get().GetUserLocalDataDir();
139}
140
141
143{
144 // Unfortunately AppData/Local is the closest analog to "Cache" directories of other platforms
145
146 // Make sure we don't include the "appinfo" (appended app name)
147
148 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
149 // complains about not existing app. so use a dummy app
150 if( wxTheApp == nullptr )
151 {
152 wxApp dummy;
153 wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
154
155 return wxStandardPaths::Get().GetUserLocalDataDir();
156 }
157
158 wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
159
160 return wxStandardPaths::Get().GetUserLocalDataDir();
161}
162
163
164bool KIPLATFORM::ENV::GetSystemProxyConfig( const wxString& aURL, PROXY_CONFIG& aCfg )
165{
166 // Original source from Microsoft sample (public domain)
167 // https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/WinhttpProxy/cpp/GetProxy.cpp#L844
168 bool autoProxyDetect = false;
169 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig = { 0 };
170 WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions = { 0 };
171 WINHTTP_PROXY_INFO autoProxyInfo = { 0 };
172 HINTERNET proxyResolveSession = NULL;
173 bool success = false;
174
175 wxURI uri( aURL );
176
177 LPWSTR proxyStr = NULL;
178 LPWSTR bypassProxyStr = NULL;
179
180 if( WinHttpGetIEProxyConfigForCurrentUser( &ieProxyConfig ) )
181 {
182 // welcome to the wonderful world of IE
183 // we use the ie config simply to handle it off to the other win32 api
184 if( ieProxyConfig.fAutoDetect )
185 {
186 autoProxyDetect = true;
187 }
188
189 if( ieProxyConfig.lpszAutoConfigUrl != NULL )
190 {
191 autoProxyDetect = true;
192 autoProxyOptions.lpszAutoConfigUrl = ieProxyConfig.lpszAutoConfigUrl;
193 }
194 }
195 else if( GetLastError() == ERROR_FILE_NOT_FOUND )
196 {
197 // this is the only error code where we want to continue attempting to find a proxy
198 autoProxyDetect = true;
199 }
200
201 if( autoProxyDetect )
202 {
203 proxyResolveSession =
204 WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME,
205 WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC );
206
207 if( proxyResolveSession )
208 {
209 // either we use the ie url or we set the auto detect mode
210 if( autoProxyOptions.lpszAutoConfigUrl != NULL )
211 {
212 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
213 }
214 else
215 {
216 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
217 autoProxyOptions.dwAutoDetectFlags =
218 WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
219 }
220
221 // dont do auto logon at first, this allows windows to use an cache
222 // per https://docs.microsoft.com/en-us/windows/win32/winhttp/autoproxy-cache
223 autoProxyOptions.fAutoLogonIfChallenged = FALSE;
224
225 autoProxyDetect = WinHttpGetProxyForUrl( proxyResolveSession, aURL.c_str(),
226 &autoProxyOptions, &autoProxyInfo );
227
228 if( !autoProxyDetect && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE )
229 {
230 autoProxyOptions.fAutoLogonIfChallenged = TRUE;
231
232 // try again with auto login now
233 autoProxyDetect = WinHttpGetProxyForUrl( proxyResolveSession, aURL.c_str(),
234 &autoProxyOptions, &autoProxyInfo );
235 }
236
237 if( autoProxyDetect )
238 {
239 if( autoProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY )
240 {
241 proxyStr = autoProxyInfo.lpszProxy;
242 bypassProxyStr = autoProxyInfo.lpszProxyBypass;
243 }
244 }
245
246 WinHttpCloseHandle( proxyResolveSession );
247 }
248 }
249
250 if( !autoProxyDetect && ieProxyConfig.lpszProxy != NULL )
251 {
252 proxyStr = ieProxyConfig.lpszProxy;
253 bypassProxyStr = ieProxyConfig.lpszProxyBypass;
254 }
255
256 bool bypassed = false;
257 if( bypassProxyStr != NULL )
258 {
259 wxStringTokenizer tokenizer( bypassProxyStr, wxT( ";" ) );
260
261 while( tokenizer.HasMoreTokens() )
262 {
263 wxString host = tokenizer.GetNextToken();
264
265 if( host == uri.GetServer() )
266 {
267 // the given url has a host in the proxy bypass list
268 return false;
269 }
270
271 // <local> is a special case that says all local sites bypass
272 // the windows way for considering local is any host without periods in the name that would imply
273 // some non-internal dns resolution
274 if( host == "<local>" )
275 {
276 if( !uri.GetServer().Contains( "." ) )
277 {
278 // great its a local uri that is bypassed
279 bypassed = true;
280 break;
281 }
282 }
283 }
284 }
285
286 if( !bypassed && proxyStr != NULL )
287 {
288 // proxyStr can be in the following format per MSDN
289 //([<scheme>=][<scheme>"://"]<server>[":"<port>])
290 //and separated by semicolons or whitespace
291 wxStringTokenizer tokenizer( proxyStr, wxT( "; \t" ) );
292
293 while( tokenizer.HasMoreTokens() )
294 {
295 wxString entry = tokenizer.GetNextToken();
296
297 // deal with the [<scheme>=] part, which may or may not exist
298 if( entry.Contains( "=" ) )
299 {
300 wxString scheme = entry.BeforeFirst( '=' ).Lower();
301 entry = entry.AfterFirst( '=' );
302
303 // skip processing if the scheme doesnt match
304 if( scheme != uri.GetScheme().Lower() )
305 {
306 continue;
307 }
308
309 // we continue with the [<scheme>=] stripped off if we matched
310 }
311
312 // is the entry left not empty? we just take the first result
313 // : and :: are also special cases we want to ignore
314 if( entry != "" && entry != ":" && entry != "::" )
315 {
316 aCfg.host = entry;
317 success = true;
318 break;
319 }
320 }
321 }
322
323
324 // We have to clean up the strings the win32 api returned
325 if( autoProxyInfo.lpszProxy )
326 {
327 GlobalFree( autoProxyInfo.lpszProxy );
328 autoProxyInfo.lpszProxy = NULL;
329 }
330
331 if( autoProxyInfo.lpszProxyBypass )
332 {
333 GlobalFree( autoProxyInfo.lpszProxyBypass );
334 autoProxyInfo.lpszProxyBypass = NULL;
335 }
336
337 if( ieProxyConfig.lpszAutoConfigUrl != NULL )
338 {
339 GlobalFree( ieProxyConfig.lpszAutoConfigUrl );
340 ieProxyConfig.lpszAutoConfigUrl = NULL;
341 }
342
343 if( ieProxyConfig.lpszProxy != NULL )
344 {
345 GlobalFree( ieProxyConfig.lpszProxy );
346 ieProxyConfig.lpszProxy = NULL;
347 }
348
349 if( ieProxyConfig.lpszProxyBypass != NULL )
350 {
351 GlobalFree( ieProxyConfig.lpszProxyBypass );
352 ieProxyConfig.lpszProxyBypass = NULL;
353 }
354
355 return success;
356}
357
358
359bool KIPLATFORM::ENV::VerifyFileSignature( const wxString& aPath )
360{
361 WINTRUST_FILE_INFO fileData;
362 memset( &fileData, 0, sizeof( fileData ) );
363 fileData.cbStruct = sizeof( WINTRUST_FILE_INFO );
364 fileData.pcwszFilePath = aPath.wc_str();
365
366 // verifies entire certificate chain
367 GUID policy = WINTRUST_ACTION_GENERIC_VERIFY_V2;
368
369 WINTRUST_DATA trustData;
370 memset( &trustData, 0, sizeof( trustData ) );
371
372 trustData.cbStruct = sizeof( trustData );
373 trustData.dwUIChoice = WTD_UI_NONE;
374 // revocation checking incurs latency penalities due to need for online queries
375 trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
376 trustData.dwUnionChoice = WTD_CHOICE_FILE;
377 trustData.dwStateAction = WTD_STATEACTION_VERIFY;
378 trustData.pFile = &fileData;
379
380
381 bool verified = false;
382 LONG status = WinVerifyTrust( NULL, &policy, &trustData );
383
384 verified = ( status == ERROR_SUCCESS );
385
386 // Cleanup/release (yes its weird looking)
387 trustData.dwStateAction = WTD_STATEACTION_CLOSE;
388 WinVerifyTrust( NULL, &policy, &trustData );
389
390 return verified;
391}
392
393
395{
396 // The application model id allows for taskbar grouping
397 // However, be warned, this cannot be too unique like per-process
398 // Because longer scope Windows features, such as "Pin to Taskbar"
399 // on a running application, depend on this being consistent.
400 std::vector<wxString> modelIdComponents;
401 modelIdComponents.push_back( wxS( "Kicad" ) );
402 modelIdComponents.push_back( wxS( "Kicad" ) );
403 modelIdComponents.push_back( wxTheApp->GetAppName() );
404 modelIdComponents.push_back( KICAD_MAJOR_MINOR_VERSION );
405
406 wxString modelId;
407 for( const auto& str : modelIdComponents )
408 {
409 modelId += str;
410 modelId += wxS( "." );
411 }
412
413 modelId.RemoveLast(); // remove trailing dot
414 modelId.Replace( wxS( " " ), wxS( "_" ) ); // remove spaces sanity
415
416 // the other limitation is 127 characters but we arent trying to hit that limit yet
417
418 return modelId;
419}
#define _(s)
bool IsNetworkPath(const wxString &aPath)
Determines if a given path is a network shared file apth On Windows for example, any form of path is ...
void Init()
Perform environment initialization tasks.
bool GetSystemProxyConfig(const wxString &aURL, PROXY_CONFIG &aCfg)
Retrieves platform level proxying requirements to reach the given url.
wxString GetUserDataPath()
Retrieves the operating system specific path for a user's data store.
wxString GetDocumentsPath()
Retrieves the operating system specific path for a user's documents.
wxString GetAppUserModelId()
Retrieves the app user model id, a special string used for taskbar grouping on Windows 7 and later.
bool MoveToTrash(const wxString &aPath, wxString &aError)
Move the specified file/directory to the trash bin/recycle bin.
wxString GetUserLocalDataPath()
Retrieves the operating system specific path for a user's local data store.
wxString GetUserConfigPath()
Retrieves the operating system specific path for a user's configuration store.
wxString GetUserCachePath()
Retrieves the operating system specific path for user's application cache.
bool VerifyFileSignature(const wxString &aPath)
Validates the code signing signature of a given file This is most likely only ever going to be applic...
std::vector< FAB_LAYER_COLOR > dummy