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 (C) 2020-2022 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#include <winhttp.h>
34
35#include <Softpub.h>
36#include <wincrypt.h>
37#include <wintrust.h>
38
39
41{
42 // No tasks for this platform
43}
44
45
46bool KIPLATFORM::ENV::MoveToTrash( const wxString& aPath, wxString& aError )
47{
48 // The filename field must be a double-null terminated string
49 wxString temp = aPath + '\0';
50
51 SHFILEOPSTRUCT fileOp;
52 ::ZeroMemory( &fileOp, sizeof( fileOp ) );
53
54 fileOp.hwnd = nullptr; // Set to null since there is no progress dialog
55 fileOp.wFunc = FO_DELETE;
56 fileOp.pFrom = temp.c_str();
57 fileOp.pTo = nullptr; // Set to to NULL since we aren't moving the file
58 fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT;
59
60 int eVal = SHFileOperation( &fileOp );
61
62 if( eVal != 0 )
63 {
64 aError = wxString::Format( _( "Error code: %d" ), eVal );
65 return false;
66 }
67
68 return true;
69}
70
71
72bool KIPLATFORM::ENV::IsNetworkPath( const wxString& aPath )
73{
74 return ::PathIsNetworkPathW( aPath.wc_str() );
75}
76
77
79{
80 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
81 // complains about not existing app. so use a dummy app
82 if( wxTheApp == nullptr )
83 {
84 wxApp dummy;
85 return wxStandardPaths::Get().GetDocumentsDir();
86 }
87
88 return wxStandardPaths::Get().GetDocumentsDir();
89}
90
91
93{
94 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
95 // complains about not existing app. so use a dummy app
96 if( wxTheApp == nullptr )
97 {
98 wxApp dummy;
99 return wxStandardPaths::Get().GetUserConfigDir();
100 }
101
102 return wxStandardPaths::Get().GetUserConfigDir();
103}
104
105
107{
108 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
109 // complains about not existing app. so use a dummy app
110 if( wxTheApp == nullptr )
111 {
112 wxApp dummy;
113 return wxStandardPaths::Get().GetUserDataDir();
114 }
115
116 return wxStandardPaths::Get().GetUserDataDir();
117}
118
119
121{
122 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
123 // complains about not existing app. so use a dummy app
124 if( wxTheApp == nullptr )
125 {
126 wxApp dummy;
127 return wxStandardPaths::Get().GetUserLocalDataDir();
128 }
129
130 return wxStandardPaths::Get().GetUserLocalDataDir();
131}
132
133
135{
136 // Unfortunately AppData/Local is the closest analog to "Cache" directories of other platforms
137
138 // Make sure we don't include the "appinfo" (appended app name)
139
140 // If called by a python script in stand-alone (outside KiCad), wxStandardPaths::Get()
141 // complains about not existing app. so use a dummy app
142 if( wxTheApp == nullptr )
143 {
144 wxApp dummy;
145 wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
146
147 return wxStandardPaths::Get().GetUserLocalDataDir();
148 }
149
150 wxStandardPaths::Get().UseAppInfo( wxStandardPaths::AppInfo_None );
151
152 return wxStandardPaths::Get().GetUserLocalDataDir();
153}
154
155
156bool KIPLATFORM::ENV::GetSystemProxyConfig( const wxString& aURL, PROXY_CONFIG& aCfg )
157{
158 // Original source from Microsoft sample (public domain)
159 // https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/WinhttpProxy/cpp/GetProxy.cpp#L844
160 bool autoProxyDetect = false;
161 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyConfig = { 0 };
162 WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions = { 0 };
163 WINHTTP_PROXY_INFO autoProxyInfo = { 0 };
164 HINTERNET proxyResolveSession = NULL;
165 bool success = false;
166
167 wxURI uri( aURL );
168
169 LPWSTR proxyStr = NULL;
170 LPWSTR bypassProxyStr = NULL;
171
172 if( WinHttpGetIEProxyConfigForCurrentUser( &ieProxyConfig ) )
173 {
174 // welcome to the wonderful world of IE
175 // we use the ie config simply to handle it off to the other win32 api
176 if( ieProxyConfig.fAutoDetect )
177 {
178 autoProxyDetect = true;
179 }
180
181 if( ieProxyConfig.lpszAutoConfigUrl != NULL )
182 {
183 autoProxyDetect = true;
184 autoProxyOptions.lpszAutoConfigUrl = ieProxyConfig.lpszAutoConfigUrl;
185 }
186 }
187 else if( GetLastError() == ERROR_FILE_NOT_FOUND )
188 {
189 // this is the only error code where we want to continue attempting to find a proxy
190 autoProxyDetect = true;
191 }
192
193 if( autoProxyDetect )
194 {
195 proxyResolveSession =
196 WinHttpOpen( NULL, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME,
197 WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC );
198
199 if( proxyResolveSession )
200 {
201 // either we use the ie url or we set the auto detect mode
202 if( autoProxyOptions.lpszAutoConfigUrl != NULL )
203 {
204 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
205 }
206 else
207 {
208 autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
209 autoProxyOptions.dwAutoDetectFlags =
210 WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
211 }
212
213 // dont do auto logon at first, this allows windows to use an cache
214 // per https://docs.microsoft.com/en-us/windows/win32/winhttp/autoproxy-cache
215 autoProxyOptions.fAutoLogonIfChallenged = FALSE;
216
217 autoProxyDetect = WinHttpGetProxyForUrl( proxyResolveSession, aURL.c_str(),
218 &autoProxyOptions, &autoProxyInfo );
219
220 if( !autoProxyDetect && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE )
221 {
222 autoProxyOptions.fAutoLogonIfChallenged = TRUE;
223
224 // try again with auto login now
225 autoProxyDetect = WinHttpGetProxyForUrl( proxyResolveSession, aURL.c_str(),
226 &autoProxyOptions, &autoProxyInfo );
227 }
228
229 if( autoProxyDetect )
230 {
231 if( autoProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY )
232 {
233 proxyStr = autoProxyInfo.lpszProxy;
234 bypassProxyStr = autoProxyInfo.lpszProxyBypass;
235 }
236 }
237
238 WinHttpCloseHandle( proxyResolveSession );
239 }
240 }
241
242 if( !autoProxyDetect && ieProxyConfig.lpszProxy != NULL )
243 {
244 proxyStr = ieProxyConfig.lpszProxy;
245 bypassProxyStr = ieProxyConfig.lpszProxyBypass;
246 }
247
248 bool bypassed = false;
249 if( bypassProxyStr != NULL )
250 {
251 wxStringTokenizer tokenizer( bypassProxyStr, wxT( ";" ) );
252
253 while( tokenizer.HasMoreTokens() )
254 {
255 wxString host = tokenizer.GetNextToken();
256
257 if( host == uri.GetServer() )
258 {
259 // the given url has a host in the proxy bypass list
260 return false;
261 }
262
263 // <local> is a special case that says all local sites bypass
264 // the windows way for considering local is any host without periods in the name that would imply
265 // some non-internal dns resolution
266 if( host == "<local>" )
267 {
268 if( !uri.GetServer().Contains( "." ) )
269 {
270 // great its a local uri that is bypassed
271 bypassed = true;
272 break;
273 }
274 }
275 }
276 }
277
278 if( !bypassed && proxyStr != NULL )
279 {
280 // proxyStr can be in the following format per MSDN
281 //([<scheme>=][<scheme>"://"]<server>[":"<port>])
282 //and separated by semicolons or whitespace
283 wxStringTokenizer tokenizer( proxyStr, wxT( "; \t" ) );
284
285 while( tokenizer.HasMoreTokens() )
286 {
287 wxString entry = tokenizer.GetNextToken();
288
289 // deal with the [<scheme>=] part, which may or may not exist
290 if( entry.Contains( "=" ) )
291 {
292 wxString scheme = entry.BeforeFirst( '=' ).Lower();
293 entry = entry.AfterFirst( '=' );
294
295 // skip processing if the scheme doesnt match
296 if( scheme != uri.GetScheme().Lower() )
297 {
298 continue;
299 }
300
301 // we continue with the [<scheme>=] stripped off if we matched
302 }
303
304 // is the entry left not empty? we just take the first result
305 // : and :: are also special cases we want to ignore
306 if( entry != "" && entry != ":" && entry != "::" )
307 {
308 aCfg.host = entry;
309 success = true;
310 break;
311 }
312 }
313 }
314
315
316 // We have to clean up the strings the win32 api returned
317 if( autoProxyInfo.lpszProxy )
318 {
319 GlobalFree( autoProxyInfo.lpszProxy );
320 autoProxyInfo.lpszProxy = NULL;
321 }
322
323 if( autoProxyInfo.lpszProxyBypass )
324 {
325 GlobalFree( autoProxyInfo.lpszProxyBypass );
326 autoProxyInfo.lpszProxyBypass = NULL;
327 }
328
329 if( ieProxyConfig.lpszAutoConfigUrl != NULL )
330 {
331 GlobalFree( ieProxyConfig.lpszAutoConfigUrl );
332 ieProxyConfig.lpszAutoConfigUrl = NULL;
333 }
334
335 if( ieProxyConfig.lpszProxy != NULL )
336 {
337 GlobalFree( ieProxyConfig.lpszProxy );
338 ieProxyConfig.lpszProxy = NULL;
339 }
340
341 if( ieProxyConfig.lpszProxyBypass != NULL )
342 {
343 GlobalFree( ieProxyConfig.lpszProxyBypass );
344 ieProxyConfig.lpszProxyBypass = NULL;
345 }
346
347 return success;
348}
349
350
351bool KIPLATFORM::ENV::VerifyFileSignature( const wxString& aPath )
352{
353 WINTRUST_FILE_INFO fileData;
354 memset( &fileData, 0, sizeof( fileData ) );
355 fileData.cbStruct = sizeof( WINTRUST_FILE_INFO );
356 fileData.pcwszFilePath = aPath.wc_str();
357
358 // verifies entire certificate chain
359 GUID policy = WINTRUST_ACTION_GENERIC_VERIFY_V2;
360
361 WINTRUST_DATA trustData;
362 memset( &trustData, 0, sizeof( trustData ) );
363
364 trustData.cbStruct = sizeof( trustData );
365 trustData.dwUIChoice = WTD_UI_NONE;
366 // revocation checking incurs latency penalities due to need for online queries
367 trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
368 trustData.dwUnionChoice = WTD_CHOICE_FILE;
369 trustData.dwStateAction = WTD_STATEACTION_VERIFY;
370 trustData.pFile = &fileData;
371
372
373 bool verified = false;
374 LONG status = WinVerifyTrust( NULL, &policy, &trustData );
375
376 verified = ( status == ERROR_SUCCESS );
377
378 // Cleanup/release (yes its weird looking)
379 trustData.dwStateAction = WTD_STATEACTION_CLOSE;
380 WinVerifyTrust( NULL, &policy, &trustData );
381
382 return verified;
383}
#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.
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