├── SetupVersion.ini ├── jq.exe ├── .gitattributes ├── unzip.exe ├── UninsIS.dll ├── syncthing.ico ├── ProcessCheck.dll ├── Localization.ini ├── shawl-license.txt ├── en-README.rtf ├── infozip-license.txt ├── jq-license.txt ├── en-SyncthingLogonTask.js ├── en-SyncthingFirewallRule.js ├── Messages-en.isl ├── en-SetSyncthingConfig.js ├── history.md ├── LICENSE ├── en-License.rtf ├── README.md └── Syncthing.iss /SetupVersion.ini: -------------------------------------------------------------------------------- 1 | [Setup] 2 | Version=2.0.0.0 3 | -------------------------------------------------------------------------------- /jq.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bill-Stewart/SyncthingWindowsSetup/HEAD/jq.exe -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /unzip.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bill-Stewart/SyncthingWindowsSetup/HEAD/unzip.exe -------------------------------------------------------------------------------- /UninsIS.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bill-Stewart/SyncthingWindowsSetup/HEAD/UninsIS.dll -------------------------------------------------------------------------------- /syncthing.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bill-Stewart/SyncthingWindowsSetup/HEAD/syncthing.ico -------------------------------------------------------------------------------- /ProcessCheck.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bill-Stewart/SyncthingWindowsSetup/HEAD/ProcessCheck.dll -------------------------------------------------------------------------------- /Localization.ini: -------------------------------------------------------------------------------- 1 | ; Localization.ini 2 | 3 | ; Allows for easy localization of the Syncthing Windows WSH scripts. 4 | ; See building.md for more information. 5 | 6 | ; NOTE: File encoding must not use a byte-order marker (BOM). 7 | 8 | [en] 9 | LicenseFile=en-License.rtf 10 | ScriptNameSetSyncthingConfig=en-SetSyncthingConfig.js 11 | ScriptNameSyncthingFirewallRule=en-SyncthingFirewallRule.js 12 | ScriptNameSyncthingLogonTask=en-SyncthingLogonTask.js 13 | -------------------------------------------------------------------------------- /shawl-license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Matthew T. Kennerly (mtkennerly) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /en-README.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset0 Calibri;}} 2 | {\*\generator Riched20 10.0.22621}\viewkind4\uc1 3 | \pard\sa200\sl240\slmult1\qc\b\fs22\lang9 About Syncthing\b0\fs20\par 4 | 5 | \pard\sa200\sl240\slmult1 Syncthing is a \b continuous file synchronization program\b0 . It synchronizes files between two or more computers. We strive to fulfill the goals below. The goals are listed in order of importance, with the most important ones first. This is the summary version of the goal list.\par 6 | Syncthing should be:\par 7 | 8 | \pard\fi-360\li360\sa200\sl240\slmult1 1.\tab\b Safe From Data Loss\b0\par 9 | 10 | \pard\li360\sa200\sl240\slmult1 Protecting the user's data is paramount. We take every reasonable precaution to avoid corrupting the user's files.\par 11 | 12 | \pard\fi-360\li360\sa200\sl240\slmult1 2.\tab\b Secure Against Attackers\b0\par 13 | 14 | \pard\li360\sa200\sl240\slmult1 Again, protecting the user's data is paramount. Regardless of our other goals, we must never allow the user's data to be susceptible to eavesdropping or modification by unauthorized parties.\par 15 | 16 | \pard\fi-360\li360\sa200\sl240\slmult1 3.\tab\b Easy to Use\b0\par 17 | 18 | \pard\li360\sa200\sl240\slmult1 Syncthing should be approachable, understandable, and inclusive.\par 19 | 20 | \pard\fi-360\li360\sa200\sl240\slmult1 4.\tab\b Automatic\b0\par 21 | 22 | \pard\li360\sa200\sl240\slmult1 User interaction should be required only when absolutely necessary.\par 23 | 24 | \pard\fi-360\li360\sa200\sl240\slmult1 5.\tab\b Universally Available\b0\par 25 | 26 | \pard\li360\sa200\sl240\slmult1 Syncthing should run on every common computer. We are mindful that the latest technology is not always available to every individual.\par 27 | 28 | \pard\fi-360\li360\sa200\sl240\slmult1 6.\tab\b For Individuals\b0\par 29 | 30 | \pard\li360\sa200\sl240\slmult1 Syncthing is primarily about empowering the individual user with safe, secure, and easy to use file synchronization.\par 31 | 32 | \pard\fi-360\li360\sa200\sl240\slmult1 7.\tab\b Everything Else\b0\par 33 | 34 | \pard\li360\sa200\sl240\slmult1 There are many things we care about that don't make it on to the list. It is fine to optimize for these values, as long as they are not in conflict with the stated goals above.\f1\fs22\par 35 | } 36 | -------------------------------------------------------------------------------- /infozip-license.txt: -------------------------------------------------------------------------------- 1 | This is version 2005-Feb-10 of the Info-ZIP copyright and license. 2 | The definitive version of this document should be available at 3 | ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. 4 | 5 | 6 | Copyright (c) 1990-2005 Info-ZIP. All rights reserved. 7 | 8 | For the purposes of this copyright and license, "Info-ZIP" is defined as 9 | the following set of individuals: 10 | 11 | Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, 12 | Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, 13 | Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, 14 | David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, 15 | Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, 16 | Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, 17 | Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, 18 | Rich Wales, Mike White 19 | 20 | This software is provided "as is," without warranty of any kind, express 21 | or implied. In no event shall Info-ZIP or its contributors be held liable 22 | for any direct, indirect, incidental, special or consequential damages 23 | arising out of the use of or inability to use this software. 24 | 25 | Permission is granted to anyone to use this software for any purpose, 26 | including commercial applications, and to alter it and redistribute it 27 | freely, subject to the following restrictions: 28 | 29 | 1. Redistributions of source code must retain the above copyright notice, 30 | definition, disclaimer, and this list of conditions. 31 | 32 | 2. Redistributions in binary form (compiled executables) must reproduce 33 | the above copyright notice, definition, disclaimer, and this list of 34 | conditions in documentation and/or other materials provided with the 35 | distribution. The sole exception to this condition is redistribution 36 | of a standard UnZipSFX binary (including SFXWiz) as part of a 37 | self-extracting archive; that is permitted without inclusion of this 38 | license, as long as the normal SFX banner has not been removed from 39 | the binary or disabled. 40 | 41 | 3. Altered versions--including, but not limited to, ports to new operating 42 | systems, existing ports with new graphical interfaces, and dynamic, 43 | shared, or static library versions--must be plainly marked as such 44 | and must not be misrepresented as being the original source. Such 45 | altered versions also must not be misrepresented as being Info-ZIP 46 | releases--including, but not limited to, labeling of the altered 47 | versions with the names "Info-ZIP" (or any variation thereof, including, 48 | but not limited to, different capitalizations), "Pocket UnZip," "WiZ" 49 | or "MacZip" without the explicit permission of Info-ZIP. Such altered 50 | versions are further prohibited from misrepresentative use of the 51 | Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). 52 | 53 | 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," 54 | "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its 55 | own source and binary releases. 56 | -------------------------------------------------------------------------------- /jq-license.txt: -------------------------------------------------------------------------------- 1 | jq is copyright (C) 2012 Stephen Dolan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | 23 | 24 | jq's documentation (everything found under the docs/ subdirectory in 25 | the source tree) is licensed under the Creative Commons CC BY 3.0 26 | license, which can be found at: 27 | 28 | https://creativecommons.org/licenses/by/3.0/ 29 | 30 | The documentation website includes a copy of Twitter's Bootstrap and 31 | relies on Bonsai, Liquid templates and various other projects, look 32 | them up for detailed licensing conditions. 33 | 34 | 35 | 36 | jq incorporates David M. Gay's dtoa.c and g_fmt.c, which bear the 37 | following notices: 38 | 39 | dtoa.c: 40 | The author of this software is David M. Gay. 41 | 42 | Copyright (c) 1991, 2000, 2001 by Lucent Technologies. 43 | 44 | Permission to use, copy, modify, and distribute this software for any 45 | purpose without fee is hereby granted, provided that this entire notice 46 | is included in all copies of any software which is or includes a copy 47 | or modification of this software and in all copies of the supporting 48 | documentation for such software. 49 | 50 | THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 51 | WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY 52 | REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 53 | OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 54 | 55 | g_fmt.c: 56 | The author of this software is David M. Gay. 57 | 58 | Copyright (c) 1991, 1996 by Lucent Technologies. 59 | 60 | Permission to use, copy, modify, and distribute this software for any 61 | purpose without fee is hereby granted, provided that this entire notice 62 | is included in all copies of any software which is or includes a copy 63 | or modification of this software and in all copies of the supporting 64 | documentation for such software. 65 | 66 | THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 67 | WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY 68 | REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 69 | OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 70 | 71 | 72 | 73 | jq uses parts of the open source C library "decNumber", which is distributed 74 | under the following license: 75 | 76 | 77 | ICU License - ICU 1.8.1 and later 78 | 79 | COPYRIGHT AND PERMISSION NOTICE 80 | 81 | Copyright (c) 1995-2005 International Business Machines Corporation and others 82 | All rights reserved. 83 | 84 | Permission is hereby granted, free of charge, to any person obtaining a 85 | copy of this software and associated documentation files (the 86 | "Software"), to deal in the Software without restriction, including 87 | without limitation the rights to use, copy, modify, merge, publish, 88 | distribute, and/or sell copies of the Software, and to permit persons 89 | to whom the Software is furnished to do so, provided that the above 90 | copyright notice(s) and this permission notice appear in all copies of 91 | the Software and that both the above copyright notice(s) and this 92 | permission notice appear in supporting documentation. 93 | 94 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 95 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 96 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 97 | OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 98 | HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 99 | INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 100 | FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 101 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 102 | WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 103 | 104 | Except as contained in this notice, the name of a copyright holder 105 | shall not be used in advertising or otherwise to promote the sale, use 106 | or other dealings in this Software without prior written authorization 107 | of the copyright holder. 108 | 109 | Portions Copyright (c) 2016 Kungliga Tekniska Högskolan 110 | (Royal Institute of Technology, Stockholm, Sweden). 111 | All rights reserved. 112 | 113 | Redistribution and use in source and binary forms, with or without 114 | modification, are permitted provided that the following conditions 115 | are met: 116 | 117 | 1. Redistributions of source code must retain the above copyright 118 | notice, this list of conditions and the following disclaimer. 119 | 120 | 2. Redistributions in binary form must reproduce the above copyright 121 | notice, this list of conditions and the following disclaimer in the 122 | documentation and/or other materials provided with the distribution. 123 | 124 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 125 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 126 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 127 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 128 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 129 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 130 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 131 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 132 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 133 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 134 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 135 | OF THE POSSIBILITY OF SUCH DAMAGE. 136 | 137 | -------------------------------------------------------------------------------- /en-SyncthingLogonTask.js: -------------------------------------------------------------------------------- 1 | // SyncthingLogonTask.js 2 | // Written by Bill Stewart (bstewart AT iname.com) for Syncthing 3 | 4 | // Notes: 5 | // * Adds a scheduled task to start Syncthing at logon 6 | // * Removes the scheduled task 7 | // * Tests whether the scheduled task exists 8 | 9 | // BEGIN LOCALIZATION 10 | var MSG_DLG_TITLE = "Syncthing"; 11 | var MSG_QUERY_CREATE = "Create scheduled task to start Syncthing at logon?"; 12 | var MSG_QUERY_REMOVE = "Remove scheduled task that starts Syncthing at logon?"; 13 | var MSG_TASK_NAME = "Start Syncthing at logon"; 14 | var MSG_ERROR_DESC_NOT_FOUND = "(No error description found)"; 15 | // END LOCALIZATION 16 | 17 | // Global Windows API constants 18 | var SW_HIDE = 0; 19 | var ERROR_FILE_NOT_FOUND = 2; 20 | var ERROR_ACCESS_DENIED = 5; 21 | // Global message box constants 22 | var MB_YESNO = 0x04; 23 | var MB_ICONERROR = 0x10; 24 | var MB_ICONQUESTION = 0x20; 25 | var IDYES = 6; 26 | // Global FileSystemObject object constants 27 | var ForReading = 1; 28 | var SystemFolder = 1; 29 | var TemporaryFolder = 2; 30 | // Global Task Scheduler object constants 31 | var TASK_ACTION_EXEC = 0; 32 | var TASK_LOGON_INTERACTIVE_TOKEN = 3; 33 | var TASK_TRIGGER_LOGON = 9; 34 | var TASK_CREATE_OR_UPDATE = 6; 35 | // Global Task Scheduler objects 36 | var TaskService = new ActiveXObject("Schedule.Service"); 37 | TaskService.Connect(); 38 | var TaskFolder = TaskService.GetFolder("\\"); 39 | // Global objects 40 | var Args = WScript.Arguments; 41 | var FSO = new ActiveXObject("Scripting.FileSystemObject"); 42 | var WshNetwork = new ActiveXObject("WScript.Network"); 43 | var WshShell = new ActiveXObject("WScript.Shell"); 44 | // Global variables 45 | var ScriptPath = WScript.ScriptFullName.substring(0,WScript.ScriptFullName.length - WScript.ScriptName.length); 46 | 47 | function trim(s) { 48 | return s.replace(/(^\s*)|(\s*$)/g, ""); 49 | } 50 | 51 | function getErrorDescription(errorCode) { 52 | // convert to unsigned if signed 53 | if ( errorCode < 0 ) { 54 | errorCode += Math.pow(2,32); 55 | } 56 | 57 | if ( errorCode.toString(0x10) == "800a0046" ) { 58 | errorCode = ERROR_ACCESS_DENIED; 59 | } 60 | 61 | // Get temporary file name 62 | do 63 | var tempName = FSO.BuildPath(FSO.GetSpecialFolder(TemporaryFolder), 64 | FSO.GetTempName()); 65 | while ( FSO.FileExists(tempName) ); 66 | 67 | // Construct command line 68 | var command = FSO.BuildPath(FSO.GetSpecialFolder(SystemFolder),"cmd.exe") + 69 | " /c " + FSO.BuildPath(ScriptPath,"ErrInfo.exe -m -n ") + 70 | errorCode.toString() + " > \"" + tempName + "\""; 71 | 72 | // Run command (output in temporary file) 73 | var exitCode = WshShell.Run(command,SW_HIDE,true); 74 | if ( exitCode == 3871 ) { 75 | errorDescription = MSG_ERROR_DESC_NOT_FOUND; 76 | } 77 | else { 78 | try { 79 | var textStream = FSO.OpenTextFile(tempName,ForReading); 80 | var errorDescription = trim(textStream.ReadAll()); 81 | } 82 | catch(err) { 83 | errorDescription = MSG_ERROR_DESC_NOT_FOUND; 84 | } 85 | finally { 86 | textStream.Close(); 87 | FSO.DeleteFile(tempName); 88 | } 89 | } 90 | 91 | if ( errorCode == 0 ) { 92 | return errorDescription; 93 | } 94 | else { 95 | return "Error " + errorCode.toString() + 96 | " [0x" + errorCode.toString(0x10).toUpperCase() + "]: " + 97 | errorDescription; 98 | } 99 | } 100 | 101 | function taskExists(taskName) { 102 | var result = false; 103 | try { 104 | TaskFolder.GetTask(taskName); 105 | result = true; 106 | } 107 | catch(err) { 108 | } 109 | return result; 110 | } 111 | 112 | function createOrUpdateLogonTask(taskName,programName,programArgs,startOnACPowerOnly) { 113 | var result = 0; 114 | var taskDefinition = TaskService.NewTask(0); // 0 parameter required 115 | var execAction = taskDefinition.Actions.Create(TASK_ACTION_EXEC); 116 | execAction.Path = programName; 117 | execAction.Arguments = programArgs; 118 | taskDefinition.Principal.LogonType = TASK_LOGON_INTERACTIVE_TOKEN; 119 | taskDefinition.Settings.DisallowStartIfOnBatteries = startOnACPowerOnly; 120 | var trigger = taskDefinition.Triggers.Create(TASK_TRIGGER_LOGON); 121 | trigger.UserId = WshNetwork.UserDomain + "\\" + WshNetwork.UserName; 122 | try { 123 | TaskFolder.RegisterTaskDefinition(taskName, // path 124 | taskDefinition, // definition 125 | TASK_CREATE_OR_UPDATE, // flags 126 | null, // userId 127 | null, // password 128 | TASK_LOGON_INTERACTIVE_TOKEN); // logonType 129 | } 130 | catch(err) { 131 | result = err.number; 132 | } 133 | return result; 134 | } 135 | 136 | function removeTask(taskName) { 137 | var result = 0; 138 | if ( taskExists(taskName) ) { 139 | try { 140 | TaskFolder.DeleteTask(taskName,0); 141 | } 142 | catch(err) { 143 | result = err.number; 144 | } 145 | } 146 | return result; 147 | } 148 | 149 | function help() { 150 | WScript.Echo("Usage: " + WScript.ScriptName + " /create [/startonacpoweronly]|/remove [/silent]"); 151 | } 152 | 153 | function reportStatus(errorCode) { 154 | if ( errorCode != 0 ) { 155 | WshShell.Popup(getErrorDescription(errorCode),0,MSG_DLG_TITLE,MB_ICONERROR); 156 | } 157 | } 158 | 159 | function query(message) { 160 | var response = WshShell.Popup(message,0,MSG_DLG_TITLE,MB_YESNO | MB_ICONQUESTION); 161 | return response == IDYES; // user clicked Yes 162 | } 163 | 164 | function getUserId() { 165 | var userId = WshNetwork.UserName + '@' + WshNetwork.UserDomain; 166 | return userId.replace('/\\\/\:\*\?\"\<\>\|/g','_'); 167 | } 168 | 169 | function main() { 170 | var result = 0; 171 | var validParams = Args.Named.Exists("create") || Args.Named.Exists("remove") || 172 | Args.Named.Exists("test"); 173 | var taskName = MSG_TASK_NAME + " (" + getUserId() + ")"; 174 | // Parse arguments 175 | if ( Args.Named.Exists("create") ) { 176 | if ( (Args.Named.Exists("silent")) || query(MSG_QUERY_CREATE) ) { 177 | var programName = FSO.BuildPath(ScriptPath,"stctl.exe"); 178 | var programArgs = '--start'; 179 | result = createOrUpdateLogonTask(taskName,programName,programArgs,Args.Named.Exists("startonacpoweronly")); 180 | } 181 | } 182 | else if ( Args.Named.Exists("remove") ) { 183 | if ( (Args.Named.Exists("silent")) || query(MSG_QUERY_REMOVE) ) { 184 | result = removeTask(taskName); 185 | } 186 | } 187 | else if ( Args.Named.Exists("test") ) { 188 | if ( ! taskExists(taskName) ) { 189 | result = ERROR_FILE_NOT_FOUND; 190 | } 191 | } 192 | if ( validParams ) { 193 | if ( ! Args.Named.Exists("silent") ) { 194 | if ( ! Args.Named.Exists("test") ) { 195 | reportStatus(result); 196 | } 197 | } 198 | } 199 | else { 200 | help(); 201 | } 202 | return result; 203 | } 204 | 205 | WScript.Quit(main()); 206 | -------------------------------------------------------------------------------- /en-SyncthingFirewallRule.js: -------------------------------------------------------------------------------- 1 | // SyncthingFirewallRule.js 2 | // Written by Bill Stewart (bstewart AT iname.com) for Syncthing 3 | 4 | // Notes: 5 | // * Adds a Windows Firewall application rule for Syncthing 6 | // * Removes the firewall rule 7 | // * Tests whether the firewall rule exists; exit code = 0 if it exists, or 8 | // ERROR_FILE_NOT_FOUND (2) if it does not exist 9 | 10 | // BEGIN LOCALIZATION 11 | var MSG_DLG_TITLE = "Syncthing"; 12 | var MSG_QUERY_CREATE_RULE = "Create Windows Firewall rule for Syncthing?"; 13 | var MSG_QUERY_REMOVE_RULE = "Remove Syncthing Windows Firewall rule?"; 14 | var MSG_ERROR_DESC_NOT_FOUND = "(No error description found)"; 15 | // END LOCALIZATION 16 | 17 | // Global Windows API constants 18 | var SW_HIDE = 0; 19 | var ERROR_FILE_NOT_FOUND = 2; 20 | var ERROR_ELEVATION_REQUIRED = 740; 21 | // Global message box constants 22 | var MB_YESNO = 0x04; 23 | var MB_ICONERROR = 0x10; 24 | var MB_ICONQUESTION = 0x20; 25 | var IDYES = 6; 26 | // Global FileSystemObject object constants 27 | var ForReading = 1; 28 | var SystemFolder = 1; 29 | var TemporaryFolder = 2; 30 | // Global objects 31 | var Args = WScript.Arguments; 32 | var FSO = new ActiveXObject("Scripting.FileSystemObject"); 33 | var WshShell = new ActiveXObject("WScript.Shell"); 34 | var NetFWPolicy2 = new ActiveXObject("HNetCfg.FWPolicy2"); 35 | // Global variables 36 | var ScriptPath = WScript.ScriptFullName.substring(0,WScript.ScriptFullName.length - WScript.ScriptName.length); 37 | var RuleName = "Syncthing"; 38 | 39 | function trim(s) { 40 | return s.replace(/(^\s*)|(\s*$)/g, ""); 41 | } 42 | 43 | function getErrorDescription(errorCode) { 44 | // convert to unsigned if signed 45 | if ( errorCode < 0 ) { 46 | errorCode += Math.pow(2,32); 47 | } 48 | 49 | if ( errorCode.toString(0x10) == "800a0046" ) { 50 | errorCode = ERROR_ELEVATION_REQUIRED; 51 | } 52 | 53 | // Get temporary file name 54 | do 55 | var tempName = FSO.BuildPath(FSO.GetSpecialFolder(TemporaryFolder), 56 | FSO.GetTempName()); 57 | while ( FSO.FileExists(tempName) ); 58 | 59 | // Construct command line 60 | var command = FSO.BuildPath(FSO.GetSpecialFolder(SystemFolder),"cmd.exe") + 61 | " /c " + FSO.BuildPath(ScriptPath,"ErrInfo.exe -m -n ") + 62 | errorCode.toString() + " > \"" + tempName + "\""; 63 | 64 | // Run command (output in temporary file) 65 | var exitCode = WshShell.Run(command,SW_HIDE,true); 66 | if ( exitCode == 3871 ) { 67 | errorDescription = MSG_ERROR_DESC_NOT_FOUND; 68 | } 69 | else { 70 | try { 71 | var textStream = FSO.OpenTextFile(tempName,ForReading); 72 | var errorDescription = trim(textStream.ReadAll()); 73 | } 74 | catch(err) { 75 | errorDescription = MSG_ERROR_DESC_NOT_FOUND; 76 | } 77 | finally { 78 | textStream.Close(); 79 | FSO.DeleteFile(tempName); 80 | } 81 | } 82 | 83 | if ( errorCode == 0 ) { 84 | return errorDescription; 85 | } 86 | else { 87 | return "Error " + errorCode.toString() + 88 | " [0x" + errorCode.toString(0x10).toUpperCase() + "]: " + 89 | errorDescription; 90 | } 91 | } 92 | 93 | function executableRuleExists(executablePath) { 94 | var result = false; 95 | try { 96 | var netFWRules = new Enumerator(NetFWPolicy2.Rules); 97 | for ( ; ! netFWRules.atEnd(); netFWRules.moveNext() ) { 98 | result = netFWRules.item().ApplicationName.toLowerCase() == executablePath.toLowerCase(); 99 | if ( result ) { 100 | break; 101 | } 102 | } 103 | } 104 | catch(err) { 105 | } 106 | return result; 107 | } 108 | 109 | function ruleExists(ruleName,executablePath) { 110 | var result = false; 111 | var netFWRule = null; 112 | try { 113 | netFWRule = NetFWPolicy2.Rules.Item(ruleName); 114 | if ( netFWRule != null ) { 115 | result = netFWRule.ApplicationName.toLowerCase() == executablePath.toLowerCase(); 116 | } 117 | } 118 | catch(err) { 119 | } 120 | return result; 121 | } 122 | 123 | function createApplicationRule(ruleName,executablePath) { 124 | var result = 0; 125 | if ( ! ruleExists(ruleName,executablePath) ) { 126 | var netFWRule = new ActiveXObject("HNetCfg.FWRule"); 127 | netFWRule.Name = ruleName; 128 | netFWRule.Action = 1; // direction=in 129 | netFWRule.ApplicationName = executablePath; 130 | netFWRule.Enabled = true; 131 | netFWRule.Protocol = 256; // no protocol restriction 132 | try { 133 | NetFWPolicy2.Rules.Add(netFWRule); 134 | } 135 | catch(err) { 136 | result = err.number; 137 | } 138 | } 139 | return result; 140 | } 141 | 142 | function removeRule(ruleName,executablePath) { 143 | var result = 0; 144 | if ( ruleExists(ruleName,executablePath) ) { 145 | try { 146 | NetFWPolicy2.Rules.Remove(ruleName); 147 | } 148 | catch(err) { 149 | result = err.number; 150 | } 151 | } 152 | return result; 153 | } 154 | 155 | function help() { 156 | WScript.Echo("Usage: " + WScript.ScriptName + " /create|/remove [/elevated [/silent]]\r\n" 157 | + "or: " + WScript.ScriptName + " /test"); 158 | } 159 | 160 | function reportStatus(errorCode) { 161 | if ( errorCode != 0 ) { 162 | WshShell.Popup(getErrorDescription(errorCode),0,MSG_DLG_TITLE,MB_ICONERROR); 163 | } 164 | } 165 | 166 | function query(message) { 167 | var response = WshShell.Popup(message,0,MSG_DLG_TITLE,MB_YESNO | MB_ICONQUESTION); 168 | return response == IDYES; // user clicked Yes 169 | } 170 | 171 | function main() { 172 | var result = 0; 173 | var syncthingPath = FSO.BuildPath(ScriptPath,"syncthing.exe"); 174 | 175 | if ( Args.Named.Exists("elevated") ) { 176 | if ( Args.Named.Exists("create") ) { 177 | result = createApplicationRule(RuleName,syncthingPath); 178 | } 179 | else if ( Args.Named.Exists("remove") ) { 180 | result = removeRule(RuleName,syncthingPath); 181 | } 182 | if ( ! Args.Named.Exists("silent") ) { 183 | reportStatus(result); 184 | } 185 | return result; 186 | } 187 | else if ( Args.Named.Exists("test") ) { 188 | if ( ! executableRuleExists(syncthingPath) ) { 189 | result = ERROR_FILE_NOT_FOUND; 190 | } 191 | return result; 192 | } 193 | 194 | // if /elevated not specified, launch self as administrator 195 | var wscriptPath = FSO.BuildPath(FSO.GetSpecialFolder(SystemFolder),"wscript.exe"); 196 | var params = '"' + WScript.ScriptFullName + '" /elevated '; 197 | var validParams = Args.Named.Exists("create") || Args.Named.Exists("remove"); 198 | if ( Args.Named.Exists("create") ) { 199 | params += " /create"; 200 | var prompt = MSG_QUERY_CREATE_RULE; 201 | } 202 | else if ( Args.Named.Exists("remove") ) { 203 | params += " /remove"; 204 | var prompt = MSG_QUERY_REMOVE_RULE; 205 | } 206 | if ( validParams ) { 207 | if ( Args.Named.Exists("silent") || query(prompt) ) { 208 | var shellApp = new ActiveXObject("Shell.Application"); 209 | shellApp.ShellExecute(wscriptPath,params,"","runas"); 210 | } 211 | } 212 | else { 213 | help(); 214 | } 215 | return result; 216 | } 217 | 218 | WScript.Quit(main()); 219 | -------------------------------------------------------------------------------- /Messages-en.isl: -------------------------------------------------------------------------------- 1 | #preproc ispp 2 | 3 | ; File encoding: UTF-8 with byte-order marker (BOM) 4 | 5 | [Messages] 6 | PrivilegesRequiredOverrideTitle=Select Setup Install Mode 7 | PrivilegesRequiredOverrideInstruction=Select install mode 8 | PrivilegesRequiredOverrideText1=%1 can be installed for all users as a Windows service (requires administrative privileges), or for the current user only. 9 | PrivilegesRequiredOverrideText2=%1 can be installed for the current user only, or for all users as a Windows service (requires administrative privileges). 10 | PrivilegesRequiredOverrideAllUsers=Install for &all users as a Windows service 11 | PrivilegesRequiredOverrideAllUsersRecommended=Install for &all users as a Windows service (recommended) 12 | PrivilegesRequiredOverrideCurrentUser=Install for ¤t user only 13 | PrivilegesRequiredOverrideCurrentUserRecommended=Install for ¤t user only (recommended) 14 | FinishedLabel=Setup has finished installing [name] on your computer. 15 | 16 | [CustomMessages] 17 | ; Uninstall display 18 | UninstallDisplayNamePerUserSuffix=(Current user) 19 | UninstallDisplayNameServiceSuffix=(Service) 20 | ; Service account 21 | ServiceAccountDescription=Syncthing service account 22 | ; Service 23 | ServiceDisplayName=Syncthing Service 24 | ServiceDescription=Syncthing securely synchronizes files between two or more computers in real time. 25 | ; [Icons] 26 | ShortcutNameConfigurationPage=Syncthing Configuration Page 27 | ShortcutNameConfigurationPageComment=Opens the Syncthing configuration web page. 28 | ShortcutNameStartSyncthing=Start Syncthing 29 | ShortcutNameStartSyncthingComment=Starts Syncthing. 30 | ShortcutNameStopSyncthing=Stop Syncthing 31 | ShortcutNameStopSyncthingComment=Stops Syncthing. 32 | ; [Tasks] 33 | TasksStartAtBoot=Start Syncthing service &automatically when system boots 34 | TasksStartServiceAfterInstall=Start Syncthing service after &installation 35 | TasksStartAtLogon=Start Syncthing &automatically when logging on 36 | TasksStartAtLogon_ACPowerOnly=S&tart automatically only if the computer is running AC power 37 | TasksStartAfterInstall=Start Syncthing after &installation 38 | TasksCreateDesktopIcon=Create &desktop shortcut for Syncthing configuration page 39 | ; [Run] 40 | RunStatusMsg=Completing setup tasks... 41 | RunPostInstallOpenConfigPage=&Open Syncthing configuration page 42 | ; Initialization 43 | InitializeSetupError0=Setup initialization error: Installation for all users is not permitted on a domain controller.%n%nSetup will now exit. 44 | InitializeSetupError1=Setup initialization error: WSH script registration is not valid.%n%nTo correct this issue, please see the "Setup Initalization Errors" section in the documentation.%n%nSetup will now exit. 45 | InitializeSetupError2=Setup initialization error: Administrative installation detected.%n%nSetup has detected that an administrative installation is already installed. To reinstall, please restart Setup with the /ALLUSERS command line option.%n%nSetup will now exit. 46 | InitializeSetupWarning0=Warning: Unable to retrieve latest version information from github.com. 47 | ; Memo pages 48 | MemoPage0Caption=License 49 | MemoPage0Description=Please see below for license information. 50 | MemoPage0SubCaption=When you are ready to continue with Setup, click Next. 51 | ; File pages 52 | FilePage0Caption=Select Installation Zip File 53 | FilePage0Description=Which zip file should Setup use to install Syncthing? 54 | FilePage0SubCaption=Specify the location of the installation zip file, then click Next. 55 | FilePage0Prompt=Syncthing &installation zip file: 56 | FilePage0Filter=Zip files (*.zip)|*.zip|All files (*)|* 57 | ; File page errors 58 | FilePage0Item0Empty=You must specify the path to the Syncthing zip file. 59 | ; Configuration pages 60 | ConfigPage0Caption=Select Configuration Settings 61 | ConfigPage0Description=How should Setup configure Syncthing? 62 | ConfigPage0SubCaption=Specify Syncthing configuration settings, then click Next. 63 | ConfigPage0Item0=Automatic &upgrade interval, in hours (0 to disable; default is %1): 64 | ConfigPage0Item1=GUI configuration page listen &address (default is %1): 65 | ConfigPage0Item2=GUI configuration page listen &port (default is %1): 66 | ConfigPage0Item3=Relays enabled ('false' or 'true', default is '%1'): 67 | ; Configuration page errors 68 | ConfigPage0Item0NotValid=The automatic upgrade interval must be in the range 0 through 65535. 69 | ConfigPage0Item1Empty=You must specify a listen address. 70 | ConfigPage0Item2NotValid=The listen port must be in the range 1024 through 65535. 71 | ConfigPage0Item3NotValid=The relays value must be 'false' or 'true'. 72 | ; Download pages 73 | DownloadPageAbortedByUser=Download aborted. 74 | ; Ready memo page 75 | ReadyMemoZipFileInfo=Installation zip file location: 76 | ReadyMemoInstallSettings=Installation settings: 77 | ReadyMemoInstallOnline=Online installation (download and install %1) 78 | ReadyMemoInstallOffline=Offline installation (use installation zip file) 79 | ReadyMemoInstallAdmin=Install for all users as Windows service 80 | ReadyMemoInstallAdminServiceAccountUserName=Service account user name: %1 81 | ReadyMemoInstallCurrentUser=Install for current user (%1) 82 | ReadyMemoConfigInfo=Configuration settings: 83 | ReadyMemoConfigItem0Disabled=Automatic upgrades are disabled 84 | ReadyMemoConfigItem0Enabled=Automatic upgrade check occurs every %1 hours 85 | ReadyMemoConfigItem1=GUI configuration page listen address is 86 | ReadyMemoConfigItem2=GUI configuration page listen port is 87 | ReadyMemoConfigItem3Disabled=Relays are disabled 88 | ReadyMemoConfigItem3Enabled=Relays are enabled 89 | ; Preparing to Install page 90 | PrepareToInstallUninstallNeeded=Setup has detected it should uninstall the currently installed version. 91 | PrepareToInstallUninstallSucceeded=Setup successfully uninstalled the currently installed version. 92 | ; Preparing to Install errors 93 | PrepareToInstallErrorMessage0=Setup was unable to uninstall the version currently installed on the system. To perform an upgrade, you must uninstall the old version that is currently installed before you will be able to install this version. 94 | PrepareToInstallErrorMessage1=Setup has detected that the installed version (%1) is newer than this version (%2). To perform a downgrade, first uninstall the installed version, and then install this version. 95 | ; DeinitializeUninstall 96 | DeinitializeUninstallAppDirRemoveSucceeded=Removed directory: %1 97 | DeinitializeUninstallAppDirRemoveFailed=Failed to remove directory: %1 98 | ; Misc. 99 | RunCommandMessage=Run command: "%1" %2 100 | ProcessCheckSucceededRunning=FindProcess function in ProcessCheck.dll succeeded; "%1" is running 101 | ProcessCheckSucceededNotRunning=FindProcess function in ProcessCheck.dll succeeded; "%1" is not running 102 | ProcessCheckFailed=FindProcess function in ProcessCheck.dll failed 103 | InstallTypeNotInstalled=The package is not detected as installed. 104 | InstallTypeAdmin=The package is detected as installed in administrative installation mode. 105 | InstallTypeNonAdmin=The package is detected as installed in non administrative installation mode. 106 | DownloadFileSucceeded=Download succeeded 107 | ZipFilePathFound=The specified zip file was found. 108 | ZipFilePathNotFound=The specified zip file was not found. 109 | ZipFileNotValid=The specified zip file is not valid. 110 | InstalledVersion=Successfully installed version %1 111 | FileDeleteSucceeded=Deleted file: %1 112 | FileDeleteFailed=Failed to delete file: %1 113 | -------------------------------------------------------------------------------- /en-SetSyncthingConfig.js: -------------------------------------------------------------------------------- 1 | // SetSyncthingConfig.js 2 | // Written by Bill Stewart (bstewart AT iname.com) for Syncthing 3 | 4 | // Notes: 5 | // * Generate config.xml if doesn't exist 6 | // * Set config.xml options requested by parameters 7 | // * Disable config.xml setLowPriority option 8 | 9 | // BEGIN LOCALIZATION 10 | var MSG_DLG_TITLE = "Syncthing"; 11 | var MSG_SYNCTHING_NOT_FOUND = "syncthing.exe not found"; 12 | var MSG_SYNCTHING_ERROR = "syncthing.exe returned an error"; 13 | var MSG_CONFIG_NOT_FOUND = "File not found:"; 14 | var MSG_CONFIG_NOT_UPDATED = "Unable to update config.xml"; 15 | // END LOCALIZATION 16 | 17 | // Global Windows API constants 18 | var SW_HIDE = 0; 19 | var ERROR_FILE_NOT_FOUND = 2; 20 | var ERROR_ALREADY_EXISTS = 183; 21 | var MB_ICONERROR = 0x10; 22 | // Global Shell.Application constants 23 | var ssfLOCALAPPDATA = 0x1C; 24 | var ssfCOMMONAPPDATA = 0x23; 25 | // Global objects 26 | var Args = WScript.Arguments; 27 | var FSO = new ActiveXObject("Scripting.FileSystemObject"); 28 | var ShellApp = new ActiveXObject("Shell.Application"); 29 | var WshShell = new ActiveXObject("WScript.Shell"); 30 | var XMLDOMDocument = new ActiveXObject("Microsoft.XMLDOM"); 31 | // Global variables 32 | var ScriptPath = WScript.ScriptFullName.substring(0,WScript.ScriptFullName.length - WScript.ScriptName.length); 33 | 34 | // Version object for comparing version number strings 'a[.b[.c[.d]]]' 35 | // compare() method returns: 36 | // * -1 if object's version < otherVersion 37 | // * 0 if object's version == otherVersion 38 | // * > 1 if object's version > otherVersion 39 | function Version(value) { 40 | var isValid = true; 41 | this.parts = value.split("."); 42 | if ( this.parts.length != 4 ) 43 | this.parts.length = 4; 44 | for ( var i = 0; i < this.parts.length; i++ ) { 45 | if ( (this.parts[i] == null) || (this.parts[i] == "") ) { 46 | var part = 0; 47 | } 48 | else { 49 | part = parseInt(this.parts[i],10); 50 | isValid = (! isNaN(part)) && (part <= 0xFFFF); 51 | } 52 | if ( ! isValid ) { 53 | this.parts = [0,0,0,0]; 54 | break; 55 | } 56 | this.parts[i] = part; 57 | } 58 | this.compare = function(otherVersion) { 59 | var result = -1; 60 | for ( var i = 0; i < 4; i++ ) { 61 | if ( this.parts[0] > otherVersion.parts[0] ) { 62 | result = 1; 63 | } 64 | else if ( this.parts[0] == otherVersion.parts[0] ) { 65 | if ( this.parts[1] > otherVersion.parts[1] ) { 66 | result = 1; 67 | } 68 | else if ( this.parts[1] == otherVersion.parts[1] ) { 69 | if ( this.parts[2] > otherVersion.parts[2] ) { 70 | result = 1; 71 | } 72 | else if ( this.parts[2] == otherVersion.parts[2] ) { 73 | if ( this.parts[3] > otherVersion.parts[3] ) { 74 | result = 1; 75 | } 76 | else if ( this.parts[3] == otherVersion.parts[3] ) { 77 | result = 0; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | return result; 84 | } 85 | } 86 | 87 | function help() { 88 | WScript.Echo("Usage: " + WScript.ScriptName + " {/currentuser|/service} [/silent]"); 89 | } 90 | 91 | function paramIsEmpty(paramName) { 92 | return (Args.Named.Item(paramName) == "") || (Args.Named.Item(paramName) == null); 93 | } 94 | 95 | function getBoolStringParam(paramName) { 96 | if ( paramIsEmpty(paramName) ) { 97 | return "false"; 98 | } 99 | return Args.Named.Item(paramName).toLowerCase() == "true" ? "true" : "false"; 100 | } 101 | 102 | function main() { 103 | // Following depend on /currentuser or /service parameter 104 | var configPath = null; // Syncthing config file path 105 | var defaultFolder = null; // Add default folder to config? 106 | var configFileName = null; // Path/filename of config.xml 107 | var generate = null; // Need to generate config.xml? 108 | 109 | if ( Args.Named.Exists("currentuser") ) { 110 | var currentUserLocalAppDataPath = ShellApp.NameSpace(ssfLOCALAPPDATA).Self.Path; 111 | configPath = FSO.BuildPath(currentUserLocalAppDataPath,"Syncthing"); 112 | defaultFolder = true; 113 | } 114 | else if ( Args.Named.Exists("service") ) { 115 | var commonAppDataPath = ShellApp.nameSpace(ssfCOMMONAPPDATA).Self.Path; 116 | configPath = FSO.BuildPath(commonAppDataPath,"Syncthing"); 117 | defaultFolder = false; 118 | } 119 | else { 120 | help(); 121 | return; 122 | } 123 | 124 | configFileName = FSO.BuildPath(configPath,"config.xml"); 125 | generate = ! FSO.FileExists(configFileName); 126 | 127 | if ( generate ) { 128 | var syncthingPath = FSO.BuildPath(ScriptPath,"syncthing.exe"); 129 | if ( ! FSO.FileExists(syncthingPath) ) { 130 | if ( ! Args.Named.Exists("silent") ) { 131 | WshShell.Popup(MSG_SYNCTHING_NOT_FOUND,0,MSG_DLG_TITLE,MB_ICONERROR); 132 | } 133 | return ERROR_FILE_NOT_FOUND; 134 | } 135 | var version = new Version(FSO.GetFileVersion(syncthingPath)); 136 | // version >= 2 uses --no-port-probing rather than --skip-port-probing 137 | portParam = version.compare(new Version("2")) >= 0 ? '--no-port-probing' : '--skip-port-probing'; 138 | var cmdLine = '"' + syncthingPath + '" generate ' + portParam + ' --home="' + configPath + '"'; 139 | if ( ! defaultFolder ) { 140 | cmdLine += ' --no-default-folder'; 141 | } 142 | // Generate configuration; fail if non-zero exit code 143 | var exitCode = WshShell.Run(cmdLine,SW_HIDE,true); 144 | if ( exitCode != 0 ) { 145 | if ( ! Args.Named.Exists("silent") ) { 146 | WshShell.Popup(MSG_SYNCTHING_ERROR,0,MSG_DLG_TITLE,MB_ICONERROR); 147 | } 148 | return exitCode; 149 | } 150 | // Fail if not found 151 | if ( ! FSO.FileExists(configFileName) ) { 152 | if ( ! Args.Named.Exists("silent") ) { 153 | WshShell.Popup(MSG_CONFIG_NOT_FOUND + "\n\n" + configFileName,0,MSG_DLG_TITLE,MB_ICONERROR); 154 | } 155 | return ERROR_FILE_NOT_FOUND; 156 | } 157 | } 158 | 159 | // Set configuration options 160 | var xmlElement = null; 161 | var configValue = null; 162 | try { 163 | XMLDOMDocument.load(configFileName); 164 | // Configure GUI address 165 | if ( Args.Named.Exists("guiaddress") ) { 166 | xmlElement = XMLDOMDocument.selectSingleNode("//configuration/gui/address"); 167 | configValue = Args.Named.Item("guiaddress"); 168 | if ( xmlElement.text != configValue ) { 169 | xmlElement.text = paramIsEmpty("guiaddress") ? "127.0.0.1:8384" : configValue; 170 | XMLDOMDocument.save(configFileName); 171 | } 172 | } 173 | // Configure autoUpgradeIntervalH 174 | if ( Args.Named.Exists("autoupgradeinterval") ) { 175 | xmlElement = XMLDOMDocument.selectSingleNode("//configuration/options/autoUpgradeIntervalH"); 176 | configValue = Args.Named.Item("autoupgradeinterval"); 177 | xmlElement.text = paramIsEmpty("autoupgradeinterval") ? "12" : configValue; 178 | XMLDOMDocument.save(configFileName); 179 | } 180 | // Configure relaysEnabled 181 | if ( Args.Named.Exists("relaysenabled") ) { 182 | xmlElement = XMLDOMDocument.selectSingleNode("//configuration/options/relaysEnabled"); 183 | configValue = getBoolStringParam("relaysenabled"); 184 | if ( xmlElement.text != configValue ) { 185 | xmlElement.text = configValue; 186 | XMLDOMDocument.save(configFileName); 187 | } 188 | } 189 | // Configure setLowPriority 190 | xmlElement = XMLDOMDocument.selectSingleNode("//configuration/options/setLowPriority"); 191 | if ( xmlElement.text.toLowerCase() != "false" ) { 192 | xmlElement.text = "false"; 193 | XMLDOMDocument.save(configFileName); 194 | } 195 | } 196 | catch(err) { 197 | if ( ! Args.Named.Exists("silent") ) { 198 | WshShell.Popup(MSG_CONFIG_NOT_UPDATED,0,MSG_DLG_TITLE,MB_ICONERROR); 199 | } 200 | return err.number; 201 | } 202 | } 203 | 204 | WScript.Quit(main()); 205 | -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | # Syncthing Windows Setup Version History 2 | 3 | Below are the release notes for Syncthing Windows Setup (herein after referred to as Setup). 4 | 5 | ## 2.0.0 (2025-08-18) 6 | 7 | * Updated [stctl](https://github.com/Bill-Stewart/stctl) to version 0.0.5. 8 | 9 | ## 1.29.1 (2025-05-30) 10 | 11 | * Updated configuration script to support Syncthing 2.0 and newer which uses the `--no-port-probing` rather than the `--skip-port-probing` parameter. (Thanks to Göran Roseen for the report.) 12 | 13 | * Improved error checking for the configuration script. 14 | 15 | * Updated [UninsIS.dll](https://github.com/Bill-Stewart/UninsIS/). 16 | 17 | * Built using Inno Setup 6.4.3. 18 | 19 | ## 1.29.0 (2025-02-21) 20 | 21 | * Updated [shawl](https://github.com/mtkennerly/shawl/) to version 1.7.0. 22 | 23 | * Added [ErrInfo](https://github.com/Bill-Stewart/ErrInfo/) for use within scripts. 24 | 25 | * Built using Inno Setup 6.4.1. 26 | 27 | ## 1.28.0 (2024-12-03) 28 | 29 | * Setup now defaults to non administrative (per user) installation mode. To install the service, you must specify the `/allusers` parameter on Setup's command line. 30 | 31 | * As a result of the above change, an administrative mode reinstall requires the `/allusers` parameter on Setup's command line. If the package is installed in administrative (all users) installation mode and you don't specify the `/allusers` parameter when reinstalling, Setup will abort with an error message. 32 | 33 | * Updated [stctl](https://github.com/Bill-Stewart/stctl/) to version 0.0.4. 34 | 35 | * Updated [shawl](https://github.com/mtkennerly/shawl/) to version 1.6.0. 36 | 37 | ## 1.27.28 (2024-10-16) 38 | 39 | * Fixed: zip file extraction now (correctly) overwrites destination files. 40 | 41 | ## 1.27.12 (2024-10-04) 42 | 43 | * Moved Setup's version number from the main wizard window title to the version number of the executable. 44 | 45 | * Setup now checks for a valid `HKEY_CLASSES_ROOT\.js` WSH script registration and aborts if the value is not correct. 46 | 47 | * Added section in documentation regarding initialization errors. 48 | 49 | ## 1.27.11 (2024-09-03) 50 | 51 | * Setup now automatically downloads and installs the latest version of Syncthing from GitHub. 52 | 53 | * Setup now also supports offline installation mode where you can specify the Syncthing download zip file. 54 | 55 | * Setup's executable size now is much smaller due to the above. 56 | 57 | * Added `desktopicon` task (not selected by default). 58 | 59 | * Added informational wizard page and moved license to a separate wizard page. 60 | 61 | * Corrected some errors in the documentation. 62 | 63 | * Built Setup using Inno Setup 6.3.3. 64 | 65 | ## 1.27.9 (2024-07-03) 66 | 67 | * Security enhancement: Prevent service installation on a domain controller. 68 | 69 | * Upgrade to Inno Setup 6.3.2. 70 | 71 | * Enhancement: Install x64 binaries on AMD64 if OS supports it. 72 | 73 | ## 1.27.6 (2024-04-12) 74 | 75 | * Fix: `startatlogon` task now appears when reinstalling and upgrading. 76 | 77 | * Added `startatlogon\acpoweronly` task. This task is disabled by default. 78 | 79 | ## 1.27.5 (2024-04-02) 80 | 81 | * Updated [shawl](https://github.com/mtkennerly/shawl) utility to v1.5.0. 82 | 83 | ## 1.27.3 (2024-02-06) 84 | 85 | * PowerShell scripts and `startps.exe` have been replaced with **[asmt](https://github.com/Bill-Stewart/asmt)**. Hopefully this will reduce anti-malware software false positives. 86 | 87 | * Start and stop scripts for per-user installations have been replaced with **[stctl](https://github.com/Bill-Stewart/stctl)**. Hopefully this will reduce anti-malware software false positives. 88 | 89 | * Setup now uses [ProcessCheck.dll](https://github.com/Bill-Stewart/ProcessCheck) to find running processes rather than a WMI query. Hopefully this will reduce anti-malware software false positives. 90 | 91 | * Minor tweaks. 92 | 93 | ## 1.27.2 (2024-01-02) 94 | 95 | * Syncthing 1.27.1 and later is built using Go >= version 1.21.5, which no longer supports Windows versions older than Windows 10/Server 2016. Accordingly, Setup requires at least Windows 10/Server 2016 or later to install Syncthing. (See https://github.com/golang/go/issues/64622 and https://forum.syncthing.net/t/21248 for further information.) 96 | 97 | * Minor tweaks. 98 | 99 | ## 1.27.1 (2023-12-11) 100 | 101 | * Added: Prevent accidental downgrades by canceling installation if installing version is lower than installed version. 102 | 103 | ## 1.27.0 (2023-12-07) 104 | 105 | * Fixed: Service reinstall did not reset the service account password under some circumstances. 106 | 107 | * Updated check for Syncthing running state to wait for up to 10 seconds at post-install. 108 | 109 | * Updated [shawl](https://github.com/mtkennerly/shawl) utility. 110 | 111 | * Changed service start/stop to the [ServMan](https://github.com/Bill-Stewart/ServMan) utility. 112 | 113 | * Changed: 114 | 115 | * Upgrading from a version older than 1.27.0 performs an automatic uninstall first. This change was made to clean up legacy upgrade code. Due to this change, if you upgrade an administrative install from version 1.19.1 the configuration will not be migrated. You must first upgrade to version 1.26.1 to migrate the configuration, and then upgrade to 1.27.0 or later. 116 | 117 | * Added `/noconfigpage` parameter to hide checkbox on post-install page. 118 | 119 | * Added `SetupVersion.ini` to manage Setup version for later upgrades. 120 | 121 | * Automatic uninstall provided by [UninsIS.dll](https://github.com/Bill-Stewart/UninsIS/). 122 | 123 | ## 1.26.0 (2023-11-06) 124 | 125 | * Fixed: Configuration file path permission not set correctly for admin installs when service account doesn't yet exist. 126 | 127 | * Changed: 128 | 129 | * Removed Setup `/nostart` command line parameter. Use the `startserviceafterinstall` (admin install mode) or `startafterinstall` (non admin install mode) tasks instead. 130 | 131 | * Updated post-install page to allow user to open the Syncthing configuration page. 132 | 133 | ## 1.25.0 (2023-10-03) 134 | 135 | * Due to a number of security vendors automatically assuming NSSM is malware (even though it was being used legitimately), Setup now uses [shawl](https://github.com/mtkennerly/shawl) to run the Windows service. (The hope is that this will reduce the number of security software false positive malware notitifications when downloading and running Setup.) 136 | 137 | * At the request of the Syncthing maintainers, relaying is now enabled by default. If you installed an older version that disabled relays by default and you want to enable relaying, do one of the following: 138 | 139 | * On the **Select Configuration Settings** page, specify `true` for the **Relays enabled** option, or 140 | * Specify `/relaysenabled=true` on the Setup command line 141 | 142 | * Removed **Configure Syncthing Service** shortcut (administrative installation mode only). 143 | 144 | * Added `Reset-SyncthingServiceAccountPassword.ps1` script (administrative installation mode only). 145 | 146 | * The name of the installed package in the Windows application list now reflects the installation mode (**admin** or **current user**). 147 | 148 | ## 1.23.7 (2023-08-10) 149 | 150 | * For new installs, Setup now defaults to non-administrative installation mode. 151 | 152 | * Added `relaysenabled` configuration item that defaults to `false`. 153 | 154 | ## 1.22.2 (2022-12-08) 155 | 156 | * Installer now installs the ARM64 version of `syncthing.exe` on that platform. 157 | 158 | * Removed **FAQ** and **Getting Started** PDF shortcuts (Syncthing team is now longer including these in the downloads). 159 | 160 | * Mozilla Public License (MPL) shows in installer as informational only rather than as a license agreement that requires acceptance to install. 161 | 162 | ## 1.22.1 (2022-12-03) 163 | 164 | * Added license page to installer. 165 | 166 | * Uninstall now deletes `syncthing.exe.old` when uninstalling. 167 | 168 | ## 1.21.0 (2022-09-10) 169 | 170 | * In 1.20.1 and older, Syncthing automatic upgrades might not work for new installations until after a reinstall. (This was because the installer was resetting the permissions of the installation folder before creating the service account.) This is now fixed. 171 | 172 | ## 1.20.1 (2022-05-11) 173 | 174 | * Setup built using Inno Setup 6.2.1. 175 | 176 | ## 1.19.2 (2022-04-14) 177 | 178 | * For improved security, administrative installation mode now configures the service to run using a local user account (by default, **SyncthingServiceAcct**) rather than the **LocalService** account. As a part of this change, the Syncthing configuration data is now located in the _CommonAppData_`\Syncthing` folder (e.g., `C:\ProgramData\Syncthing`). 179 | 180 | * When upgrading an administrative installation from 1.19.1 or older, Setup automatically migrates the Syncthing configuration data from the legacy **LocalService** account user profile (e.g., `C:\Windows\ServiceProfiles\LocalService\ApplicationData\Local\Syncthing`) to the updated configuration data folder (e.g., `C:\ProgramData\Syncthing`). If the migration succeeds, Setup offers to remove the legacy configuration folder. (A silent installation will automatically remove the legacy configuration folder if the migration succeeded.) 181 | 182 | > NOTE: If you upgrade an administrative installation of 1.19.1 or older, please see `README.md` for instructions on how to grant the service's local user account "Modify" permissions to folder(s) in the Syncthing configuration. 183 | 184 | * The `startatboot` task (i.e., **the Start Syncthing service automatically when system boots** checkbox on the **Select Additional Tasks** page) in administrative installation mode configures the Windows service accordingly when reinstalling or upgrading. 185 | 186 | ## 1.19.1 (2022-03-16) 187 | 188 | * No Setup changes. 189 | 190 | ## 1.19.0 (2022-02-02) 191 | 192 | * `SetSyncthingConfig.js` no longer requires firewall rule (thanks to Syncthing maintainers for adding `--skip-port-probing` option). 193 | 194 | ## 1.18.6.5 (2022-01-19) 195 | 196 | * Fix: No error dialog from `SetSyncthingConfig.js` script if running silently. 197 | 198 | * Fix: If GUI listen address specified as "any" (`0.0.0.0` or `::`), then set `ConfigurationPage.url` to use `127.0.0.1`. 199 | 200 | * Minor tweaks. 201 | 202 | ## 1.18.6.4 (2022-01-14) 203 | 204 | * Fixed wrong `SetSyncthingConfig.js` included in build. 205 | 206 | ## 1.18.6.3 (2022-01-13) 207 | 208 | * Fix: Setup now looks up localized account name for `NT AUTHORITY\LOCAL SERVICE` when installing service. 209 | 210 | ## 1.18.6.2 (2022-01-12) 211 | 212 | * Fix: Configuration wasn't being generated correctly for Windows service. 213 | 214 | * Fix: Don't show `startatboot` task if service is already installed. 215 | 216 | * Improved: `StopSyncthing.js` uses CLI command (`syncthing cli operations shutdown`) to stop Syncthing. 217 | 218 | ## 1.18.6 (2022-01-11) 219 | 220 | > NOTE: If you installed Syncthing 1.18.5 using Setup, it is recommended to uninstall it first before installing 1.18.6 or any newer version. This is recommended due to the improved way that Setup handles configuration settings in 1.18.6 and newer. 221 | 222 | * Setup now remembers configuration page data between runs. 223 | 224 | * Improved firewall rule detection. 225 | 226 | * Removed `allowautoupgrade` task and replaced it with the `/autoupgradeinterval` parameter (specifies number of hours between automatic upgrade checks). This value is also settable during interactive install on the configuration wizard page. 227 | 228 | * Added `InitSyncthingConfig.js` script for updating `config.xml`: 229 | 230 | * Configures automatic upgrade interval (in hours) 231 | 232 | * Configures GUI configuration page address and port 233 | 234 | * Configures `setLowPriority` setting to `false` 235 | 236 | Setup runs this script when installing so that the user's preferences get written to `config.xml`. 237 | 238 | * Non administrative (current user) installation no longer writes Syncthing configuration data to the registry. 239 | 240 | ## 1.18.5 (2021-12-28) 241 | 242 | * Initial version. 243 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | 9 | means each individual or legal entity that creates, contributes to 10 | the creation of, or owns Covered Software. 11 | 12 | 1.2. "Contributor Version" 13 | 14 | means the combination of the Contributions of others (if any) used 15 | by a Contributor and that particular Contributor's Contribution. 16 | 17 | 1.3. "Contribution" 18 | 19 | means Covered Software of a particular Contributor. 20 | 21 | 1.4. "Covered Software" 22 | 23 | means Source Code Form to which the initial Contributor has 24 | attached the notice in Exhibit A, the Executable Form of such 25 | Source Code Form, and Modifications of such Source Code Form, in 26 | each case including portions thereof. 27 | 28 | 1.5. "Incompatible With Secondary Licenses" 29 | 30 | means 31 | 32 | (a) that the initial Contributor has attached the notice described 33 | in Exhibit B to the Covered Software; or 34 | 35 | (b) that the Covered Software was made available under the terms 36 | of version 1.1 or earlier of the License, but not also under 37 | the terms of a Secondary License. 38 | 39 | 1.6. "Executable Form" 40 | 41 | means any form of the work other than Source Code Form. 42 | 43 | 1.7. "Larger Work" 44 | 45 | means a work that combines Covered Software with other material, 46 | in a separate file or files, that is not Covered Software. 47 | 48 | 1.8. "License" 49 | 50 | means this document. 51 | 52 | 1.9. "Licensable" 53 | 54 | means having the right to grant, to the maximum extent possible, 55 | whether at the time of the initial grant or subsequently, any and 56 | all of the rights conveyed by this License. 57 | 58 | 1.10. "Modifications" 59 | 60 | means any of the following: 61 | 62 | (a) any file in Source Code Form that results from an addition to, 63 | deletion from, or modification of the contents of Covered 64 | Software; or 65 | 66 | (b) any new file in Source Code Form that contains any Covered 67 | Software. 68 | 69 | 1.11. "Patent Claims" of a Contributor 70 | 71 | means any patent claim(s), including without limitation, method, 72 | process, and apparatus claims, in any patent Licensable by such 73 | Contributor that would be infringed, but for the grant of the 74 | License, by the making, using, selling, offering for sale, having 75 | made, import, or transfer of either its Contributions or its 76 | Contributor Version. 77 | 78 | 1.12. "Secondary License" 79 | 80 | means either the GNU General Public License, Version 2.0, the GNU 81 | Lesser General Public License, Version 2.1, the GNU Affero General 82 | Public License, Version 3.0, or any later versions of those 83 | licenses. 84 | 85 | 1.13. "Source Code Form" 86 | 87 | means the form of the work preferred for making modifications. 88 | 89 | 1.14. "You" (or "Your") 90 | 91 | means an individual or a legal entity exercising rights under this 92 | License. For legal entities, "You" includes any entity that 93 | controls, is controlled by, or is under common control with You. 94 | For purposes of this definition, "control" means (a) the power, 95 | direct or indirect, to cause the direction or management of such 96 | entity, whether by contract or otherwise, or (b) ownership of more 97 | than fifty percent (50%) of the outstanding shares or beneficial 98 | ownership of such entity. 99 | 100 | 2. License Grants and Conditions 101 | -------------------------------- 102 | 103 | 2.1. Grants 104 | 105 | Each Contributor hereby grants You a world-wide, royalty-free, 106 | non-exclusive license: 107 | 108 | (a) under intellectual property rights (other than patent or trademark) 109 | Licensable by such Contributor to use, reproduce, make available, 110 | modify, display, perform, distribute, and otherwise exploit its 111 | Contributions, either on an unmodified basis, with Modifications, or 112 | as part of a Larger Work; and 113 | 114 | (b) under Patent Claims of such Contributor to make, use, sell, offer 115 | for sale, have made, import, and otherwise transfer either its 116 | Contributions or its Contributor Version. 117 | 118 | 2.2. Effective Date 119 | 120 | The licenses granted in Section 2.1 with respect to any Contribution 121 | become effective for each Contribution on the date the Contributor first 122 | distributes such Contribution. 123 | 124 | 2.3. Limitations on Grant Scope 125 | 126 | The licenses granted in this Section 2 are the only rights granted under 127 | this License. No additional rights or licenses will be implied from the 128 | distribution or licensing of Covered Software under this License. 129 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 130 | Contributor: 131 | 132 | (a) for any code that a Contributor has removed from Covered Software; 133 | or 134 | 135 | (b) for infringements caused by: (i) Your and any other third party's 136 | modifications of Covered Software, or (ii) the combination of its 137 | Contributions with other software (except as part of its Contributor 138 | Version); or 139 | 140 | (c) under Patent Claims infringed by Covered Software in the absence of 141 | its Contributions. 142 | 143 | This License does not grant any rights in the trademarks, service marks, 144 | or logos of any Contributor (except as may be necessary to comply with 145 | the notice requirements in Section 3.4). 146 | 147 | 2.4. Subsequent Licenses 148 | 149 | No Contributor makes additional grants as a result of Your choice to 150 | distribute the Covered Software under a subsequent version of this 151 | License (see Section 10.2) or under the terms of a Secondary License (if 152 | permitted under the terms of Section 3.3). 153 | 154 | 2.5. Representation 155 | 156 | Each Contributor represents that the Contributor believes its 157 | Contributions are its original creation(s) or it has sufficient rights 158 | to grant the rights to its Contributions conveyed by this License. 159 | 160 | 2.6. Fair Use 161 | 162 | This License is not intended to limit any rights You have under 163 | applicable copyright doctrines of fair use, fair dealing, or other 164 | equivalents. 165 | 166 | 2.7. Conditions 167 | 168 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 169 | in Section 2.1. 170 | 171 | 3. Responsibilities 172 | ------------------- 173 | 174 | 3.1. Distribution of Source Form 175 | 176 | All distribution of Covered Software in Source Code Form, including any 177 | Modifications that You create or to which You contribute, must be under 178 | the terms of this License. You must inform recipients that the Source 179 | Code Form of the Covered Software is governed by the terms of this 180 | License, and how they can obtain a copy of this License. You may not 181 | attempt to alter or restrict the recipients' rights in the Source Code 182 | Form. 183 | 184 | 3.2. Distribution of Executable Form 185 | 186 | If You distribute Covered Software in Executable Form then: 187 | 188 | (a) such Covered Software must also be made available in Source Code 189 | Form, as described in Section 3.1, and You must inform recipients of 190 | the Executable Form how they can obtain a copy of such Source Code 191 | Form by reasonable means in a timely manner, at a charge no more 192 | than the cost of distribution to the recipient; and 193 | 194 | (b) You may distribute such Executable Form under the terms of this 195 | License, or sublicense it under different terms, provided that the 196 | license for the Executable Form does not attempt to limit or alter 197 | the recipients' rights in the Source Code Form under this License. 198 | 199 | 3.3. Distribution of a Larger Work 200 | 201 | You may create and distribute a Larger Work under terms of Your choice, 202 | provided that You also comply with the requirements of this License for 203 | the Covered Software. If the Larger Work is a combination of Covered 204 | Software with a work governed by one or more Secondary Licenses, and the 205 | Covered Software is not Incompatible With Secondary Licenses, this 206 | License permits You to additionally distribute such Covered Software 207 | under the terms of such Secondary License(s), so that the recipient of 208 | the Larger Work may, at their option, further distribute the Covered 209 | Software under the terms of either this License or such Secondary 210 | License(s). 211 | 212 | 3.4. Notices 213 | 214 | You may not remove or alter the substance of any license notices 215 | (including copyright notices, patent notices, disclaimers of warranty, 216 | or limitations of liability) contained within the Source Code Form of 217 | the Covered Software, except that You may alter any license notices to 218 | the extent required to remedy known factual inaccuracies. 219 | 220 | 3.5. Application of Additional Terms 221 | 222 | You may choose to offer, and to charge a fee for, warranty, support, 223 | indemnity or liability obligations to one or more recipients of Covered 224 | Software. However, You may do so only on Your own behalf, and not on 225 | behalf of any Contributor. You must make it absolutely clear that any 226 | such warranty, support, indemnity, or liability obligation is offered by 227 | You alone, and You hereby agree to indemnify every Contributor for any 228 | liability incurred by such Contributor as a result of warranty, support, 229 | indemnity or liability terms You offer. You may include additional 230 | disclaimers of warranty and limitations of liability specific to any 231 | jurisdiction. 232 | 233 | 4. Inability to Comply Due to Statute or Regulation 234 | --------------------------------------------------- 235 | 236 | If it is impossible for You to comply with any of the terms of this 237 | License with respect to some or all of the Covered Software due to 238 | statute, judicial order, or regulation then You must: (a) comply with 239 | the terms of this License to the maximum extent possible; and (b) 240 | describe the limitations and the code they affect. Such description must 241 | be placed in a text file included with all distributions of the Covered 242 | Software under this License. Except to the extent prohibited by statute 243 | or regulation, such description must be sufficiently detailed for a 244 | recipient of ordinary skill to be able to understand it. 245 | 246 | 5. Termination 247 | -------------- 248 | 249 | 5.1. The rights granted under this License will terminate automatically 250 | if You fail to comply with any of its terms. However, if You become 251 | compliant, then the rights granted under this License from a particular 252 | Contributor are reinstated (a) provisionally, unless and until such 253 | Contributor explicitly and finally terminates Your grants, and (b) on an 254 | ongoing basis, if such Contributor fails to notify You of the 255 | non-compliance by some reasonable means prior to 60 days after You have 256 | come back into compliance. Moreover, Your grants from a particular 257 | Contributor are reinstated on an ongoing basis if such Contributor 258 | notifies You of the non-compliance by some reasonable means, this is the 259 | first time You have received notice of non-compliance with this License 260 | from such Contributor, and You become compliant prior to 30 days after 261 | Your receipt of the notice. 262 | 263 | 5.2. If You initiate litigation against any entity by asserting a patent 264 | infringement claim (excluding declaratory judgment actions, 265 | counter-claims, and cross-claims) alleging that a Contributor Version 266 | directly or indirectly infringes any patent, then the rights granted to 267 | You by any and all Contributors for the Covered Software under Section 268 | 2.1 of this License shall terminate. 269 | 270 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 271 | end user license agreements (excluding distributors and resellers) which 272 | have been validly granted by You or Your distributors under this License 273 | prior to termination shall survive termination. 274 | 275 | ************************************************************************ 276 | * * 277 | * 6. Disclaimer of Warranty * 278 | * ------------------------- * 279 | * * 280 | * Covered Software is provided under this License on an "as is" * 281 | * basis, without warranty of any kind, either expressed, implied, or * 282 | * statutory, including, without limitation, warranties that the * 283 | * Covered Software is free of defects, merchantable, fit for a * 284 | * particular purpose or non-infringing. The entire risk as to the * 285 | * quality and performance of the Covered Software is with You. * 286 | * Should any Covered Software prove defective in any respect, You * 287 | * (not any Contributor) assume the cost of any necessary servicing, * 288 | * repair, or correction. This disclaimer of warranty constitutes an * 289 | * essential part of this License. No use of any Covered Software is * 290 | * authorized under this License except under this disclaimer. * 291 | * * 292 | ************************************************************************ 293 | 294 | ************************************************************************ 295 | * * 296 | * 7. Limitation of Liability * 297 | * -------------------------- * 298 | * * 299 | * Under no circumstances and under no legal theory, whether tort * 300 | * (including negligence), contract, or otherwise, shall any * 301 | * Contributor, or anyone who distributes Covered Software as * 302 | * permitted above, be liable to You for any direct, indirect, * 303 | * special, incidental, or consequential damages of any character * 304 | * including, without limitation, damages for lost profits, loss of * 305 | * goodwill, work stoppage, computer failure or malfunction, or any * 306 | * and all other commercial damages or losses, even if such party * 307 | * shall have been informed of the possibility of such damages. This * 308 | * limitation of liability shall not apply to liability for death or * 309 | * personal injury resulting from such party's negligence to the * 310 | * extent applicable law prohibits such limitation. Some * 311 | * jurisdictions do not allow the exclusion or limitation of * 312 | * incidental or consequential damages, so this exclusion and * 313 | * limitation may not apply to You. * 314 | * * 315 | ************************************************************************ 316 | 317 | 8. Litigation 318 | ------------- 319 | 320 | Any litigation relating to this License may be brought only in the 321 | courts of a jurisdiction where the defendant maintains its principal 322 | place of business and such litigation shall be governed by laws of that 323 | jurisdiction, without reference to its conflict-of-law provisions. 324 | Nothing in this Section shall prevent a party's ability to bring 325 | cross-claims or counter-claims. 326 | 327 | 9. Miscellaneous 328 | ---------------- 329 | 330 | This License represents the complete agreement concerning the subject 331 | matter hereof. If any provision of this License is held to be 332 | unenforceable, such provision shall be reformed only to the extent 333 | necessary to make it enforceable. Any law or regulation which provides 334 | that the language of a contract shall be construed against the drafter 335 | shall not be used to construe this License against a Contributor. 336 | 337 | 10. Versions of the License 338 | --------------------------- 339 | 340 | 10.1. New Versions 341 | 342 | Mozilla Foundation is the license steward. Except as provided in Section 343 | 10.3, no one other than the license steward has the right to modify or 344 | publish new versions of this License. Each version will be given a 345 | distinguishing version number. 346 | 347 | 10.2. Effect of New Versions 348 | 349 | You may distribute the Covered Software under the terms of the version 350 | of the License under which You originally received the Covered Software, 351 | or under the terms of any subsequent version published by the license 352 | steward. 353 | 354 | 10.3. Modified Versions 355 | 356 | If you create software not governed by this License, and you want to 357 | create a new license for such software, you may create and use a 358 | modified version of this License if you rename the license and remove 359 | any references to the name of the license steward (except to note that 360 | such modified license differs from this License). 361 | 362 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 363 | Licenses 364 | 365 | If You choose to distribute Source Code Form that is Incompatible With 366 | Secondary Licenses under the terms of this version of the License, the 367 | notice described in Exhibit B of this License must be attached. 368 | 369 | Exhibit A - Source Code Form License Notice 370 | ------------------------------------------- 371 | 372 | This Source Code Form is subject to the terms of the Mozilla Public 373 | License, v. 2.0. If a copy of the MPL was not distributed with this 374 | file, You can obtain one at https://mozilla.org/MPL/2.0/. 375 | 376 | If it is not possible or desirable to put the notice in a particular 377 | file, then You may include the notice in a location (such as a LICENSE 378 | file in a relevant directory) where a recipient would be likely to look 379 | for such a notice. 380 | 381 | You may add additional accurate notices of copyright ownership. 382 | 383 | Exhibit B - "Incompatible With Secondary Licenses" Notice 384 | --------------------------------------------------------- 385 | 386 | This Source Code Form is "Incompatible With Secondary Licenses", as 387 | defined by the Mozilla Public License, v. 2.0. 388 | -------------------------------------------------------------------------------- /en-License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fswiss\fprq2\fcharset128 Arial;}} 2 | {\colortbl ;\red255\green255\blue0;\red0\green0\blue255;} 3 | {\*\generator Riched20 10.0.22621}\viewkind4\uc1 4 | \pard\qc\b\fs22\lang9 Mozilla Public License Version 2.0\par 5 | 6 | \pard\hyphpar0\widctlpar\kerning1\b0\f1\fs20\lang1033\par 7 | 8 | \pard\fi-720\li720\kerning0\b\f0 1.\tab Definitions\par 9 | 10 | \pard\hyphpar0\widctlpar\kerning1\b0\par 11 | 12 | \pard\fi-720\li720\kerning0\b 1.1.\tab "Contributor"\par 13 | 14 | \pard\hyphpar0\widctlpar\kerning1\b0\par 15 | 16 | \pard\li720\kerning0 means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software.\par 17 | 18 | \pard\hyphpar0\widctlpar\kerning1\par 19 | 20 | \pard\fi-720\li720\kerning0\b 1.2.\tab "Contributor Version"\par 21 | 22 | \pard\hyphpar0\widctlpar\kerning1\b0\par 23 | 24 | \pard\li720\kerning0 means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution.\par 25 | 26 | \pard\hyphpar0\widctlpar\kerning1\par 27 | 28 | \pard\fi-720\li720\kerning0\b 1.3.\tab "Contribution"\par 29 | 30 | \pard\hyphpar0\widctlpar\kerning1\b0\par 31 | 32 | \pard\li720\kerning0 means Covered Software of a particular Contributor.\par 33 | 34 | \pard\hyphpar0\widctlpar\kerning1\par 35 | 36 | \pard\fi-720\li720\kerning0\b 1.4.\tab "Covered Software"\par 37 | 38 | \pard\hyphpar0\widctlpar\kerning1\b0\par 39 | 40 | \pard\li720\kerning0 means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof.\par 41 | 42 | \pard\hyphpar0\widctlpar\kerning1\par 43 | 44 | \pard\fi-720\li720\kerning0\b 1.5.\tab "Incompatible With Secondary Licenses"\par 45 | 46 | \pard\hyphpar0\widctlpar\kerning1\b0\par 47 | 48 | \pard\li720\kerning0 means\par 49 | 50 | \pard\hyphpar0\widctlpar\kerning1\par 51 | 52 | \pard\fi-720\li1440\kerning0 (a)\tab that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or\par 53 | 54 | \pard\hyphpar0\widctlpar\kerning1\par 55 | 56 | \pard\fi-720\li1440\kerning0 (b)\tab that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License.\par 57 | 58 | \pard\hyphpar0\widctlpar\kerning1\par 59 | 60 | \pard\fi-720\li720\kerning0\b 1.6.\tab "Executable Form"\par 61 | 62 | \pard\hyphpar0\widctlpar\kerning1\b0\par 63 | 64 | \pard\li720\kerning0 means any form of the work other than Source Code Form.\par 65 | 66 | \pard\hyphpar0\widctlpar\kerning1\par 67 | 68 | \pard\fi-720\li720\kerning0\b 1.7.\tab "Larger Work"\par 69 | 70 | \pard\hyphpar0\widctlpar\kerning1\b0\par 71 | 72 | \pard\li720\kerning0 means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software.\par 73 | 74 | \pard\hyphpar0\widctlpar\kerning1\par 75 | 76 | \pard\fi-720\li720\kerning0\b 1.8.\tab "License"\par 77 | 78 | \pard\hyphpar0\widctlpar\kerning1\b0\par 79 | 80 | \pard\li720\kerning0 means this document.\par 81 | 82 | \pard\hyphpar0\widctlpar\kerning1\par 83 | 84 | \pard\fi-720\li720\kerning0\b 1.9.\tab "Licensable"\par 85 | 86 | \pard\hyphpar0\widctlpar\kerning1\b0\par 87 | 88 | \pard\li720\kerning0 means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License.\par 89 | 90 | \pard\hyphpar0\widctlpar\kerning1\par 91 | 92 | \pard\fi-720\li720\kerning0\b 1.10.\tab "Modifications"\par 93 | 94 | \pard\hyphpar0\widctlpar\kerning1\b0\par 95 | 96 | \pard\li720\kerning0 means any of the following:\par 97 | 98 | \pard\hyphpar0\widctlpar\kerning1\par 99 | 100 | \pard\fi-720\li1440\kerning0 (a)\tab any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or\par 101 | 102 | \pard\hyphpar0\widctlpar\kerning1\par 103 | 104 | \pard\fi-720\li1440\kerning0 (b)\tab any new file in Source Code Form that contains any Covered Software.\par 105 | 106 | \pard\hyphpar0\widctlpar\kerning1\par 107 | 108 | \pard\fi-720\li720\kerning0\b 1.11.\tab "Patent Claims" of a Contributor\par 109 | 110 | \pard\hyphpar0\widctlpar\kerning1\b0\par 111 | 112 | \pard\li720\kerning0 means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version.\par 113 | 114 | \pard\hyphpar0\widctlpar\kerning1\par 115 | 116 | \pard\fi-720\li720\kerning0\b 1.12.\tab "Secondary License"\par 117 | 118 | \pard\hyphpar0\widctlpar\kerning1\b0\par 119 | 120 | \pard\li720\kerning0 means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses.\par 121 | 122 | \pard\hyphpar0\widctlpar\kerning1\par 123 | 124 | \pard\fi-720\li720\kerning0\b 1.13.\tab "Source Code Form"\par 125 | 126 | \pard\hyphpar0\widctlpar\kerning1\b0\par 127 | 128 | \pard\li720\kerning0 means the form of the work preferred for making modifications.\par 129 | 130 | \pard\hyphpar0\widctlpar\kerning1\par 131 | 132 | \pard\fi-720\li720\kerning0\b 1.14.\tab "You" (or "Your")\par 133 | 134 | \pard\hyphpar0\widctlpar\kerning1\b0\par 135 | 136 | \pard\li720\kerning0 means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.\par 137 | 138 | \pard\hyphpar0\widctlpar\kerning1\par 139 | 140 | \pard\fi-720\li720\kerning0\b 2.\tab License Grants and Conditions\par 141 | 142 | \pard\hyphpar0\widctlpar\kerning1\b0\par 143 | 144 | \pard\fi-720\li720\kerning0\b 2.1.\tab Grants\par 145 | 146 | \pard\hyphpar0\widctlpar\kerning1\b0\par 147 | Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:\par 148 | \par 149 | 150 | \pard\fi-720\li720\kerning0 (a)\tab under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and\par 151 | \par 152 | (b)\tab under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version.\par 153 | 154 | \pard\hyphpar0\widctlpar\kerning1\par 155 | 156 | \pard\fi-720\li720\kerning0\b 2.2.\tab Effective Date\par 157 | 158 | \pard\hyphpar0\widctlpar\kerning1\b0\par 159 | The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution.\par 160 | \par 161 | 162 | \pard\fi-720\li720\kerning0\b 2.3.\tab Limitations on Grant Scope\par 163 | 164 | \pard\hyphpar0\widctlpar\kerning1\b0\par 165 | The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor:\par 166 | \par 167 | 168 | \pard\fi-720\li720\kerning0 (a)\tab for any code that a Contributor has removed from Covered Software; or\par 169 | \par 170 | (b)\tab for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or\par 171 | \par 172 | (c)\tab under Patent Claims infringed by Covered Software in the absence of its Contributions.\par 173 | 174 | \pard\hyphpar0\widctlpar\kerning1\par 175 | This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4).\par 176 | \par 177 | 178 | \pard\fi-720\li720\kerning0\b 2.4.\tab Subsequent Licenses\par 179 | 180 | \pard\hyphpar0\widctlpar\kerning1\b0\par 181 | No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3).\par 182 | \par 183 | 184 | \pard\fi-720\li720\kerning0\b 2.5.\tab Representation\par 185 | 186 | \pard\hyphpar0\widctlpar\kerning1\b0\par 187 | Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License.\par 188 | \par 189 | 190 | \pard\fi-720\li720\kerning0\b 2.6.\tab Fair Use\par 191 | 192 | \pard\hyphpar0\widctlpar\kerning1\b0\par 193 | This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.\par 194 | \par 195 | 196 | \pard\fi-720\li720\kerning0\b 2.7.\tab Conditions\par 197 | 198 | \pard\hyphpar0\widctlpar\kerning1\b0\par 199 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1.\par 200 | \par 201 | 202 | \pard\fi-720\li720\kerning0\b 3.\tab Responsibilities\par 203 | 204 | \pard\hyphpar0\widctlpar\kerning1\b0\par 205 | 206 | \pard\fi-720\li720\kerning0\b 3.1.\tab Distribution of Source Form\par 207 | 208 | \pard\hyphpar0\widctlpar\kerning1\b0\par 209 | All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form.\par 210 | \par 211 | 212 | \pard\fi-720\li720\kerning0\b 3.2.\tab Distribution of Executable Form\par 213 | 214 | \pard\hyphpar0\widctlpar\kerning1\b0\par 215 | If You distribute Covered Software in Executable Form then:\par 216 | \par 217 | 218 | \pard\fi-720\li720\kerning0 (a)\tab such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and\par 219 | \par 220 | (b)\tab You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License.\par 221 | 222 | \pard\hyphpar0\widctlpar\kerning1\par 223 | 224 | \pard\fi-720\li720\kerning0\b 3.3.\tab Distribution of a Larger Work\par 225 | 226 | \pard\hyphpar0\widctlpar\kerning1\b0\par 227 | You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s).\par 228 | \par 229 | 230 | \pard\fi-720\li720\kerning0\b 3.4.\tab Notices\par 231 | 232 | \pard\hyphpar0\widctlpar\kerning1\b0\par 233 | You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies.\par 234 | \par 235 | 236 | \pard\fi-720\li720\kerning0\b 3.5.\tab Application of Additional Terms\par 237 | 238 | \pard\hyphpar0\widctlpar\kerning1\b0\par 239 | You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction.\par 240 | \par 241 | 242 | \pard\fi-720\li720\kerning0\b 4.\tab Inability to Comply Due to Statute or Regulation\par 243 | 244 | \pard\hyphpar0\widctlpar\kerning1\b0\par 245 | If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.\par 246 | \par 247 | 248 | \pard\fi-720\li720\kerning0\b 5.\tab Termination\par 249 | 250 | \pard\hyphpar0\widctlpar\kerning1\b0\par 251 | 5.1.\tab The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice.\par 252 | \par 253 | 5.2.\tab If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.\par 254 | \par 255 | 5.3.\tab In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination.\par 256 | \par 257 | 258 | \pard\fi-720\li720\kerning0\b 6.\tab Disclaimer of Warranty\par 259 | 260 | \pard\hyphpar0\widctlpar\kerning1\b0\par 261 | 262 | \pard\cbpat1\li720\ri720\highlight1\kerning0 Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer.\par 263 | 264 | \pard\hyphpar0\widctlpar\highlight0\kerning1\par 265 | 266 | \pard\fi-720\li720\kerning0\b 7.\tab Limitation of Liability\par 267 | 268 | \pard\hyphpar0\widctlpar\kerning1\b0\par 269 | 270 | \pard\cbpat1\li720\ri720\highlight1\kerning0 Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.\highlight0\par 271 | 272 | \pard\hyphpar0\widctlpar\kerning1\par 273 | 274 | \pard\fi-720\li720\kerning0\b 8.\tab Litigation\par 275 | 276 | \pard\hyphpar0\widctlpar\kerning1\b0\par 277 | Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims.\par 278 | \par 279 | 280 | \pard\fi-720\li720\kerning0\b 9.\tab Miscellaneous\par 281 | 282 | \pard\hyphpar0\widctlpar\kerning1\b0\par 283 | This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor.\par 284 | \par 285 | 286 | \pard\fi-720\li720\kerning0\b 10.\tab Versions of the License\par 287 | 288 | \pard\hyphpar0\widctlpar\kerning1\b0\par 289 | 290 | \pard\fi-720\li720\kerning0\b 10.1.\tab New Versions\par 291 | 292 | \pard\hyphpar0\widctlpar\kerning1\b0\par 293 | Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number.\par 294 | \par 295 | 296 | \pard\fi-720\li720\kerning0\b 10.2.\tab Effect of New Versions\par 297 | 298 | \pard\hyphpar0\widctlpar\kerning1\b0\par 299 | You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward.\par 300 | \par 301 | 302 | \pard\fi-720\li720\kerning0\b 10.3.\tab Modified Versions\par 303 | 304 | \pard\hyphpar0\widctlpar\kerning1\b0\par 305 | If you create software not governed by this License, and you want to create a new license for such software, you may create and use a version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License).\par 306 | \par 307 | 308 | \pard\fi-720\li720\kerning0\b 10.4.\tab Distributing Source Code Form that is Incompatible With Secondary Licenses\par 309 | 310 | \pard\hyphpar0\widctlpar\kerning1\b0\par 311 | If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached.\par 312 | \par 313 | 314 | \pard\fi-720\li720\kerning0\b Exhibit A - Source Code Form License Notice\par 315 | 316 | \pard\hyphpar0\widctlpar\kerning1\b0\par 317 | 318 | \pard\li720\ri720\kerning0 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 {{\field{\*\fldinst{HYPERLINK https://mozilla.org/MPL/2.0/ }}{\fldrslt{https://mozilla.org/MPL/2.0/\ul0\cf0}}}}\f0\fs20 .\par 319 | 320 | \pard\hyphpar0\widctlpar\kerning1\par 321 | If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.\par 322 | \par 323 | You may add additional accurate notices of copyright ownership.\par 324 | \par 325 | 326 | \pard\fi-720\li720\kerning0\b Exhibit B - "Incompatible With Secondary Licenses" Notice\par 327 | 328 | \pard\hyphpar0\widctlpar\kerning1\b0\par 329 | 330 | \pard\li720\ri720\kerning0 This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.\par 331 | } 332 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Syncthing Windows Setup 3 | 4 | Syncthing Windows Setup is a lightweight yet full-featured Windows installer for the open-source [Syncthing](https://syncthing.net) file-synchronization application. 5 | 6 | --- 7 | 8 | 9 | ## Table of Contents 10 | 11 | - [System Requirements](#system-requirements) 12 | - [Download](#download) 13 | - [Background](#background) 14 | - [Version History](#version-history) 15 | - [Upgrade Details](#upgrade-details) 16 | - [Downgrading an Installation](#downgrading-an-installation) 17 | - [Changing Installation Type](#changing-installation-type) 18 | - [Setup Initialization Errors](#setup-initialization-errors) 19 | - [Installation for All Users not Allowed on Domain Controllers](#installation-for-all-users-not-allowed-on-domain-controllers) 20 | - [Invalid WSH Script Registration](#invalid-wsh-script-registration) 21 | - [Administrative Installation Detected](#administrative-installation-detected) 22 | - [Setup Command Line Parameters](#setup-command-line-parameters) 23 | - [Offline Installation](#offline-installation) 24 | - [Non Administrative vs. Administrative Installation Mode](#non-administrative-vs-administrative-installation-mode) 25 | - [Non Administrative (Current User) Installation Mode](#non-administrative-current-user-installation-mode) 26 | - [Administrative (All Users) Installation Mode](#administrative-all-users-installation-mode) 27 | - [Windows Service Installation](#windows-service-installation) 28 | - [Local User Service Account Considerations](#local-user-service-account-considerations) 29 | - [Granting Folder Permissions for the Service Account](#granting-folder-permissions-for-the-service-account) 30 | - [Setup Tasks](#setup-tasks) 31 | - [Start Menu Shortcuts](#start-menu-shortcuts) 32 | - [Managing Automatic Startup](#managing-automatic-startup) 33 | - [Managing Automatic Startup for the Current User](#managing-automatic-startup-for-the-current-user) 34 | - [Managing Automatic Startup for the Windows Service (All Users)](#managing-automatic-startup-for-the-windows-service-all-users) 35 | - [Checking If Syncthing Is Running](#checking-if-syncthing-is-running) 36 | - [Checking if Syncthing is Running for the Current User](#checking-if-syncthing-is-running-for-the-current-user) 37 | - [Checking if Syncthing is Running as a Service](#checking-if-syncthing-is-running-as-a-service) 38 | - [Windows Firewall Rules](#windows-firewall-rules) 39 | - [Firewall Rule Creation](#firewall-rule-creation) 40 | - [Creating the Firewall Rule Manually](#creating-the-firewall-rule-manually) 41 | - [Firewall Rule Removal](#firewall-rule-removal) 42 | - [Removing the Firewall Rule Manually](#removing-the-firewall-rule-manually) 43 | - [Helper Tools](#helper-tools) 44 | - [Resetting the Service Account Password](#resetting-the-service-account-password) 45 | - [Finding the Syncthing Configuration Folder](#finding-the-syncthing-configuration-folder) 46 | - [Uninstalling Syncthing](#uninstalling-syncthing) 47 | - [Silent Install and Uninstall](#silent-install-and-uninstall) 48 | - [Silent Non Administrative (Current User) Installation](#silent-non-administrative-current-user-installation) 49 | - [Silent Administrative (All Users) Installation](#silent-administrative-all-users-installation) 50 | - [Silent Uninstall](#silent-uninstall) 51 | - [Reporting Problems](#reporting-problems) 52 | - [Acknowledgments](#acknowledgments) 53 | 54 | --- 55 | 56 | ## System Requirements 57 | 58 | Syncthing Windows Setup has the same requirements as Syncthing itself: Windows 10 or Windows Server 2016 or later. 59 | 60 | ## Download 61 | 62 | You can download the latest version of Syncthing Windows Setup from the Github Releases page: 63 | 64 | https://github.com/Bill-Stewart/SyncthingWindowsSetup/releases/latest/ 65 | 66 | ## Background 67 | 68 | Syncthing Windows Setup (herein referred to as "Setup") provides a [Syncthing](https://syncthing.net/) installer for Windows, built using [Inno Setup](https://www.jrsoftware.org/isinfo.php). It provides the following features: 69 | 70 | * Downloads and installs the latest version of Syncthing from GitHub 71 | 72 | * Supports offline installation for Windows-based computers that can't connect to GitHub (see [Offline Installation](#offline-installation)) 73 | 74 | * Supports non administrative (current user) and administrative (all users) installation (see [Non Administrative vs. Administrative Installation Mode](#non-administrative-vs-administrative-installation-mode)) 75 | 76 | * When installing for the current user (the default), Setup creates a scheduled task that starts Syncthing at logon (if selected) 77 | 78 | * When installing for all users, installs Syncthing as a Windows service (see [Windows Service Installation](#windows-service-installation)) 79 | 80 | * Supports adding a Windows Firewall rule for Syncthing (see [Windows Firewall Rules](#windows-firewall-rules)) 81 | 82 | * Installs a set of helper tools for ease-of-use (see [Helper Tools](#helper-tools)) 83 | 84 | * Supports silent (hands-free) installation (see [Silent Install and Uninstall](#silent-install-and-uninstall)) 85 | 86 | * Allows localization of Setup and scripts (see `building.md` file for details) 87 | 88 | ## Version History 89 | 90 | See `history.md`. 91 | 92 | ## Upgrade Details 93 | 94 | Administrative installations in versions 1.19.1 and older configured the Windows service to run using the Windows built-in **LocalService** account. To improve security, Setup versions newer than 1.19.1 configure the Windows service to run using a local service user account instead (**SyncthingServiceAcct** by default). As a part of this change, the Syncthing configuration data is now located in the _CommonAppData_`\Syncthing` folder (e.g., `C:\ProgramData\Syncthing`). 95 | 96 | If you upgrade an administrative installation from version 1.19.1 or older, Setup version 1.27.0 and newer will uninstall the old version and install the new version, but it will no longer migrate the configuration data. Because of this change, it is recommended to first upgrade to version 1.26.1 to migrate the configuration data, and then upgrade again to version 1.27.0 or later. 97 | 98 | Starting in version 1.27.11, Setup automatically downloads and installs the latest version of Syncthing for Windows from GitHub. If Setup can't connect to GitHub, you must perform an offline installation (see [Offline Installation](#offline-installation)). 99 | 100 | ## Downgrading an Installation 101 | 102 | To downgrade a Syncthing installation, do the following: 103 | 104 | 1. Disable Syncthing's automatic upgrade setting. 105 | 106 | 2. Stop Syncthing. 107 | 108 | 3. Manually replace the `syncthing.exe` file with your preferred version. 109 | 110 | 4. Start Syncthing. 111 | 112 | > NOTE: If you run Setup to reinstall or upgrade Syncthing, the **Automatic upgrade interval** setting on the **Select Configuration Settings** wizard page (or the `/autoupgradeinterval` command-line parameter) will override the **Automatic Upgrades** setting in the Syncthing configuration GUI. 113 | 114 | ## Changing Installation Type 115 | 116 | If you installed using non administrative (current user) installation mode and want to use administrative (all users) installation mode instead (or vice versa), you must uninstall and reinstall using your preferred installation mode. 117 | 118 | If you want to keep the same configuration, you will need to replace the content of the Syncthing configuration folder. The location of the Syncthing configuration folder depends on the installation mode; see [Finding the Syncthing Configuration Folder](#finding-the-syncthing-configuration-folder) for details. 119 | 120 | ## Setup Initialization Errors 121 | 122 | This section discusses potential errors that may occur during Setup's initialization phase that will abort the installation process. 123 | 124 | ### Installation for All Users not Allowed on Domain Controllers 125 | 126 | For various reasons, Setup does not permit installation for all users (i.e., the Windows service) on Active Directory domain controller servers. If you need to run Syncthing on domain controllers, this author's recommendation is to run `syncthing.exe` using a Group Managed Service Account (gMSA). See Microsoft's documentation for more information about gMSAs. 127 | 128 | ### Invalid WSH Script Registration 129 | 130 | Setup uses Windows Script Host (WSH) scripts to perform a number of tasks. On some computers, the WSH script registration for JScript (`.js`) files on the computer is missing or incorrect. To ensure it can complete successfully, Setup checks for the following value in the registry: 131 | 132 | Path: `HKEY_CLASSES_ROOT\.js` 133 | Default value: `JSFile` 134 | 135 | Setup will abort if this registry value is not correct. To fix this problem, use whatever tool you prefer (e.g., the Windows Registry Editor) to correct the default value at this registry location to `JSFile`. For example, you can run the following command from an elevated command line (cmd.exe or PowerShell) window: 136 | 137 | reg add "HKCR\.js" /ve /d "JSFile" 138 | 139 | ### Administrative Installation Detected 140 | 141 | If Setup detects that the package is installed in administrative (all users) installation mode and you did not specify the `/allusers` parameter on Setup's command line, it will abort the installation and instruct the user to restart setup with the `/allusers` parameter. 142 | 143 | ## Setup Command Line Parameters 144 | 145 | The following table lists the most common Setup command line parameters: 146 | 147 | Parameter | Description 148 | --------- | ----------- 149 | `/currentuser` | Runs Setup in non-administrative (current user) installation mode (see [Non Administrative vs. Administrative Installation Mode](#non-administrative-vs-administrative-installation-mode)). This is the default and is recommended for most users. 150 | `/allusers` | Runs Setup in administrative (all users) installation mode (see [Non Administrative vs. Administrative Installation Mode](#non-administrative-vs-administrative-installation-mode)). This installs the Windows service and is recommended for more advanced users. NOTE: You must specify this parameter if performing a reinstall in administrative (all users) installation mode, even if the package is already installed. 151 | `/dir="`_location_`"` | Specifies the installation folder. The default installation folder depends on whether Setup runs in administrative (all users) or non administrative (current user) installation mode. 152 | `/group="`_name_`"` | Specifies the Start Menu group name. The default group name is **Syncthing**. 153 | `/tasks="`_task_[`,`_task_[...]]`"` | Selects one or more tasks on the **Select Additional Tasks** wizard page (see [Setup Tasks](#setup-tasks)). 154 | `/mergetasks="`_task_[`,`_task_[...]]`"` | Like `/tasks`, except Setup merges the specified tasks with the set of tasks that would have otherwise been selected by default. 155 | `/noicons` | Prevents creation of a Start Menu group. 156 | `/silent` | Runs Setup without requiring user interaction (see [Silent Install and Uninstall](#silent-install-and-uninstall)). 157 | `/log="`_filename_`"` | Logs Setup activity to the specified file. The default is not to create a log file. 158 | 159 | See [Inno Setup's documentation](https://jrsoftware.org/ishelp/index.php?topic=setupcmdline) for more details about the above parameters. 160 | 161 | In addition to the standard Inno Setup parameters, Setup also supports some custom command line parameters. The parameters marked with **[*]** correspond to the settings on the **Select Configuration Settings** page in Setup. 162 | 163 | Parameter | Description 164 | --------- | ----------- 165 | `/autoupgradeinterval=`_interval_ | **[*]** Specifies the number of hours that Syncthing should check for upgrades and automatically upgrade itself. The default value is 12 hours. Specify **0** to disable Syncthing's automatic upgrade feature. 166 | `/listenaddress=`_address_ | **[*]** Specifies the listen address for the web GUI configuration page. The default listen address is **127.0.0.1**. 167 | `/listenport=`_port_ | **[*]** Specifies the TCP port number for the web GUI configuration page. The default port number is **8384**. 168 | `/relaysenabled=`_value_ | **[*]** Specifies whether relays are enabled (_value_ must be either **true** or **false**). The default value is **true** (i.e., relays are enabled). 169 | `/serviceaccountusername=`_username_ | For administrative installation mode, specifies the local service user account user name. The default user name is **SyncthingServiceAcct**. 170 | `/noconfigpage` | Prevents the **Open Syncthing configuration page** checkbox from appearing on the final Setup wizard page. 171 | `/zipfilepath="`_filename_`"` | Specifies the path and filename of the zip file Setup uses to extract the Syncthing files (see [Offline Installation](#offline-installation)). 172 | 173 | Please note the following: 174 | 175 | * The `/autoupgradeinterval` parameter affects the `syncthing.exe` executable only (it does not download or run a new version of Setup). If this setting is greater than 0 and Syncthing detects a new version released by the Syncthing team on the Internet, Syncthing will upgrade itself. (The Syncthing configuration GUI also allows enabling or disabling automatic upgrading, but reinstalling or upgrading Syncthing using Setup will override the configuration GUI setting.) 176 | 177 | * Please read the [Syncthing documentation page about the GUI listen address](https://docs.syncthing.net/users/guilisten.html) before changing the listen address and port numbers from the defaults. 178 | 179 | * For more information about relays, please see the [Syncthing documentation page about relaying](https://docs.syncthing.net/users/relaying). Please note that relaying might trigger network security alerts if an outgoing connection is made to a relay network host on the Internet that is being shared by a network service prohibited by network security teams on business or government networks. It is recommended to check with network security teams before using Syncthing on these kinds of networks. 180 | 181 | * It is recommended not to use the `/serviceaccountusername` parameter to change the local service account user name except in the extremely rare case that the username is already in use. 182 | 183 | ## Offline Installation 184 | 185 | For Windows-based computers that are unable to download files from GitHub using https, Setup supports offline installation. To facilitate offline installation, you must download the zip file for the Windows version of Syncthing from a separate computer that can connect to GitHub. You can download the latest version of the zip file from the Syncthing project's **Releases** page: 186 | 187 | https://github.com/syncthing/syncthing/releases/latest 188 | 189 | The zip file uses the following format: 190 | 191 | `syncthing-windows-`_platform_`-v`_version_`.zip` 192 | 193 | Where: 194 | 195 | * _platform_ is one of the following: **amd64**, **386**, or **arm64** 196 | 197 | * _version_ is the Syncthing version number 198 | 199 | For example: `syncthing-windows-amd64-v1.27.11.zip` (**amd64** is the most common version) 200 | 201 | Once you have the zip file, you can specify it for Setup by doing one of the following: 202 | 203 | * Select the installation zip file on the **Select Installation Zip File** wizard page in Setup, or 204 | 205 | * Specify the full path and filename of the installation zip file using the **/zipfilepath** parameter on Setup's command line (see [Setup Command Line Parameters](#setup-command-line-parameters)). 206 | 207 | Please note the following behaviors: 208 | 209 | * If Setup can't connect to GitHub to retrieve the latest Syncthing version information, it will assume an offline installation and display the **Select Installation Zip File** wizard page. 210 | 211 | * If you specify the **/zipfilepath** parameter, Setup will not attempt to connect to GetHub to retrieve Syncthing version information or download the latest installation zip file. 212 | 213 | ## Non Administrative vs. Administrative Installation Mode 214 | 215 | By default, Setup installs Syncthing for the current user only. This is recommeded for most users. 216 | 217 | If you want to install Syncthing as a Windows service (recommended for more advanced users), you must specify the `/allusers` parameter on Setup's command line (see [Setup Command Line Parameters](#setup-command-line-parameters)). This parameter is also required if you want to reinstall the service. 218 | 219 | > NOTE: Installing in administrative (all users) installation mode means you must manually configure folder permissions to add folders to the Syncthing configuration (see [Granting Folder Permissions for the Service Account](#granting-folder-permissions-for-the-service-account)). 220 | 221 | See below for the differences between the two modes. 222 | 223 | ### Non Administrative (Current User) Installation Mode 224 | 225 | Non administrative (current user) installation mode is the default and is recommended for most users. The following notes apply to this installation mode: 226 | 227 | * Setup installs Syncthing for the current user only 228 | 229 | * The default installation folder is _LocalAppData_`\Programs\Syncthing` (where _LocalAppData_ is the current user's local application data folder; e.g., `C:\Users\UserName\AppData\Local`) 230 | 231 | * The Syncthing configuration folder is _LocalAppData_`\Syncthing` (e.g., `C:\Users\UserName\AppData\Local`; see [Finding the Syncthing Configuration Folder](#finding-the-syncthing-configuration-folder)) 232 | 233 | * Setup does not install Syncthing as a Windows service 234 | 235 | * By default, Setup creates a scheduled task that starts Syncthing in the background when the current user logs on; you can change this by deselecting the **Start Syncthing automatically when logging on** checkbox on the **Select Additional Tasks** wizard page 236 | 237 | * Syncthing runs only when the installing user logs on 238 | 239 | * Starting and stopping Syncthing is managed by [Start Menu shortcuts](#start-menu-shortcuts) 240 | 241 | * Setup prompts to create a Windows Firewall rule for Syncthing (requires administrative permissions) 242 | 243 | * By default, Setup starts Syncthing after installation completes if a firewall rule exists for it; you can change this by deselecting the **Start Syncthing after installation** checkbox on the **Select Additional Tasks** wizard page 244 | 245 | * No folder permission changes are required to add the current user's folders to the Syncthing configuration 246 | 247 | * Administrative permissions are not required to make changes to files in the Syncthing configuration folder 248 | 249 | ### Administrative (All Users) Installation Mode 250 | 251 | Administrative (all users) installation mode installs Syncthing as a Windows service and is recommended only for more advanced users. The following notes apply to this installation mode: 252 | 253 | * Setup installs Syncthing for all users of the computer 254 | 255 | * The default installation folder is _ProgramFiles_`\Syncthing` (where _ProgramFiles_ is the system's `Program Files` folder; e.g., `C:\Program Files`) 256 | 257 | * The Syncthing configuration folder is _CommonAppData_`\Syncthing` (e.g., `C:\ProgramData\Syncthing`; see [Finding the Syncthing Configuration Folder](#finding-the-syncthing-configuration-folder)) 258 | 259 | * Setup installs Syncthing as a Windows service (see [Windows Service Installation](#windows-service-installation)) 260 | 261 | * By default, Syncthing starts automatically when the system boots; you can change this by deselecting the **Start Syncthing service automatically when system boots** checkbox on the **Select Additional Tasks** wizard page 262 | 263 | * Syncthing runs as a service and synchronizes folders even when no users are logged on 264 | 265 | * Starting and stopping Syncthing is managed by stopping and starting the Windows service 266 | 267 | * Setup automatically creates a Windows Firewall rule for Syncthing 268 | 269 | * By default, Setup starts the Syncthing service after installation completes; you can change this by deselecting the **Start Syncthing service after installation** checkbox on the **Select Additional Tasks** wizard page 270 | 271 | * You must manually grant folder permissions for folders you want to add to the Syncthing configuration (see [Granting Folder Permissions for the Service Account](#granting-folder-permissions-for-the-service-account)) 272 | 273 | * Administrative permissions are required to make changes to files in the Syncthing configuration folder 274 | 275 | > NOTE: You must specify `/allusers` on Setup's command line to install or reinstall in administrative (all users) installation mode. 276 | 277 | #### Windows Service Installation 278 | 279 | When you run Setup in administrative (all users) installation mode, it installs Syncthing as a Windows service. The service runs using a local service account (**SyncthingServiceAcct** by default). By default, Setup configures the service to start at boot. You can change this default by deselecting the `startatboot` task when installing (see [Setup Tasks](#setup-tasks)). 280 | 281 | #### Local User Service Account Considerations 282 | 283 | In administrative installation mode, Setup setup creates or updates the local service user account (**SyncthingServiceAcct** by default) with a very long, random password and configures the following settings for the account: 284 | 285 | * It sets the account's password not to expire 286 | 287 | * It grants the account the **Log on as a service** user right 288 | 289 | If the computer is joined to a domain, be aware that Group Policy Object (GPO) settings might override either or both of these settings for the local service user account, which can prevent the service from working. If GPO settings override either or both of these settings, you can do either of the following: 290 | 291 | * Uninstall the administrative installation of Syncthing and install for the current user instead, or 292 | 293 | * Update the relevant GPO(s) to prevent overriding of the setting(s). 294 | 295 | #### Granting Folder Permissions for the Service Account 296 | 297 | In administrative (all users) installation mode, Syncthing runs as a Windows service using a local service user account (**SyncthingServiceAcct** by default). Normally the local service user account does not have permissions to folders you want to synchronize using Syncthing. This means you must grant the local service user account "Modify" permissions to any folders specified in the Syncthing configuration. 298 | 299 | You can grant the local service user account "Modify" permissions to a folder using the Windows File Explorer. Alternatively, you can run the **icacls** command from the command line; e.g.: 300 | 301 | icacls "C:\Users\username\Documents" /grant "SyncthingServiceAcct:(OI)(CI)M" /t 302 | 303 | Of course, replace `C:\Users\username\Documents` with the correct folder name, and replace `SyncthingServiceAcct` with the correct service account user name if you changed the default service account user name. 304 | 305 | Once the local service user account has "Modify" permissions for the folder, you can add it to the Syncthing configuration. 306 | 307 | > NOTE: Granting folder permissions is normally only needed if you installed Syncthing in administrative (all users) installation mode. 308 | 309 | ## Setup Tasks 310 | 311 | The **Select Additional Tasks** wizard page in Setup specifies additional tasks that Setup should perform, as described in the following table: 312 | 313 | Task Description | Name | Installation Mode 314 | ---------------- | ---- | ----------------- 315 | Start Syncthing automatically when logging on | `startatlogon` | Current user 316 | Start automatically only if the computer is running AC power | `startatlogon\acpoweronly` | Current user 317 | Start Syncthing after installation | `startafterinstall` | Current user 318 | Start Syncthing service automatically when system boots | `startatboot` | All users 319 | Start Syncthing service after installation | `startserviceafterinstall` | All users 320 | Create desktop shortcut for Syncthing configuration page | `desktopicon` | Both 321 | 322 | The `/tasks` and `/mergetasks` command line parameters (see [Setup Command Line Parameters](#setup-command-line-parameters)) allow you to select and deselect tasks using the command line. By default, all tasks are selected except for the following: 323 | 324 | * `startatlogon\acpoweronly` 325 | * `desktopicon` 326 | 327 | Examples: 328 | 329 | * Create a desktop shortcut in addition to all other tasks selected by default: 330 | 331 | `/mergetasks=desktopicon` 332 | 333 | * For an administrative installation, do not start the Syncthing service after installation, but leave all other default tasks selected: 334 | 335 | `/mergetasks=!startserviceafterinstall` 336 | 337 | * For a non administrative installation, specify only to start Syncthing at logon and do not select any other tasks: 338 | 339 | `/tasks=startatlogon` 340 | 341 | * Remove the desktop shortcut during a reinstall and do not change the state of any other tasks: 342 | 343 | `/mergetasks=!desktopicon` 344 | 345 | See [Inno Setup's documentation](https://jrsoftware.org/ishelp/index.php?topic=setupcmdline) for more details about the `/tasks` and `/mergetasks` command line parameters. 346 | 347 | ## Start Menu Shortcuts 348 | 349 | Setup creates the following Start Menu shortcuts, depending on the [installation mode](#administrative-vs-non-administrative-installation-mode): 350 | 351 | Shortcut | Installation Mode | Description 352 | -------- | ----------------- | ----------- 353 | Syncthing Configuration Page | Both | Opens the Syncthing GUI configuration page using the default browser 354 | Start Syncthing | Current user | Starts Syncthing in the background for the current user 355 | Stop Syncthing | Current user | Stops the Syncthing instance running for the current user 356 | 357 | * The **Syncthing Configuration Page** shortcut opens the `ConfigurationPage.url` file in the Syncthing installation folder (i.e., it opens the Syncthing GUI configuration page). 358 | 359 | * The **Start Syncthing** and **Stop Syncthing** shortcuts run the `stctl.exe` tool to start and stop Syncthing (see [Helper Tools](#helper-tools)). 360 | 361 | ## Managing Automatic Startup 362 | 363 | Setup configures Syncthing to start automatically by default, unless you deselect the `startatlogon` or `startatboot` task (see [Setup Tasks](#setup-tasks)). You can change this configuration after installation if needed. The steps for changing the configuration depends on whether you installed using non administrative (current user) or administrative (all users) or installation mode. 364 | 365 | ### Managing Automatic Startup for the Current User 366 | 367 | If you installed Syncthing for the current user, Setup creates a scheduled task that starts Syncthing automatically when the current user logs on. Setup does not create this task if you deselect the `startatlogon` task (see [Setup Tasks](#setup-tasks)) when installing. 368 | 369 | If you did not select the `startatlogon` task when installing and want to create the task, do either of the following: 370 | 371 | * Run setup to reinstall Syncthing and select the `startatlogon` task (i.e., the **Start Syncthing automatically when logging on** checkbox on the **Select Additional Tasks** page). 372 | 373 | OR 374 | 375 | 1. Open a command prompt or PowerShell window. 376 | 377 | 2. Run the following command: 378 | 379 | cscript "C:\Users\username\AppData\Local\Programs\Syncthing\SyncthingLogonTask.js" /create 380 | 381 | (where `C:\Users\username\appData\Local\Programs\Syncthing` is the Syncthing installation folder; replace `username` with the correct username) 382 | 383 | If you want to disable the logon task instead, do the following: 384 | 385 | 1. Open the Windows Task Scheduler application. 386 | 387 | 2. Right-click the **Start Syncthing at logon (_username_)** task and choose **Disable**. 388 | 389 | ### Managing Automatic Startup for the Windows Service (All Users) 390 | 391 | If you installed Syncthing for all users (i.e., the Windows service is installed), do the following: 392 | 393 | * Run Setup with the `/allusers` parameter to reinstall Syncthing and select or deselect the `startatboot` task (i.e., the **Start Syncthing service automatically when system boots** checkbox on the **Select Additional Tasks** page). 394 | 395 | OR 396 | 397 | 1. Open the Windows Services application. 398 | 399 | 2. Double-click the Syncthing service. 400 | 401 | 3. Change **Startup type** to **Automatic (Delayed Start)** or **Manual**, then Click **OK**. 402 | 403 | Note that these steps require administrative permissions. 404 | 405 | ## Checking If Syncthing Is Running 406 | 407 | This section describes how to check if Syncthing is running. 408 | 409 | ### Checking if Syncthing is Running for the Current User 410 | 411 | If you ran Setup in non administrative (current user) mode, do one of the following: 412 | 413 | 1. Open the Windows Task Manager application. 414 | 415 | 2. Switch to the "details" view to see the list of running applications. 416 | 417 | 3. Check whether `syncthing.exe` is in the list. 418 | 419 | OR 420 | 421 | 1. Open a command prompt or PowerShell window. 422 | 423 | 2. Enter the following command: 424 | 425 | tasklist /fi "imagename eq syncthing.exe" 426 | 427 | The output of this command will indicate whether Syncthing is currently running. 428 | 429 | > NOTE: No matter whether you use the Task Manager application or the **tasklist** command, it is normal for there to be more than one running instance of `syncthing.exe`. 430 | 431 | ### Checking if Syncthing is Running as a Service 432 | 433 | If you ran Setup in administrative (all users) installation mode, do the following: 434 | 435 | 1. Open the Windows Services application. 436 | 437 | 2. Find the Syncthing service in the list. 438 | 439 | 3. The **Status** column will indicate if the Syncthing service is running. 440 | 441 | > NOTE: The **tasklist** command in the previous section also works to check if the service is running, except that the **Session Name** column in the output will contain _Services_ rather than _Console_. 442 | 443 | ## Windows Firewall Rules 444 | 445 | Syncthing requires permission to communicate through the Windows Firewall. Creating and removing firewall rules requires administrative privileges. 446 | 447 | ### Firewall Rule Creation 448 | 449 | * If you run Setup in non administrative (current user) installation mode, Setup prompts to create a firewall rule for Syncthing if it doesn't exist. Setup will prompt for administrative credentials (if needed). 450 | 451 | * If you perform a silent install in non administrative installation mode (see [Setup Command Line Parameters](#setup-command-line-parameters)), Setup does not create a firewall rule for Syncthing, and you must create it manually (see [Creating the Firewall Rule Manually](#creating-the-firewall-rule-manually)). 452 | 453 | * If you run Setup in administrative (all users) installation mode, Setup creates a firewall rule for Syncthing automatically. 454 | 455 | ### Creating the Firewall Rule Manually 456 | 457 | If you ran Setup using non administrative installation mode and need to create a firewall rule for Syncthing manually, open a PowerShell or command prompt window and run the following command: 458 | 459 | cscript "C:\Users\username\AppData\Local\Programs\Syncthing\SyncthingFirewallRule.js" /create 460 | 461 | (where `C:\Users\username\appData\Local\Programs\Syncthing` is the Syncthing installation folder; replace `username` with the correct username) 462 | 463 | ### Firewall Rule Removal 464 | 465 | If you uninstall Syncthing (see [Uninstalling Syncthing](#uninstalling-syncthing)), the same considerations as above apply, except Setup removes the Syncthing firewall rule rather than creating it: 466 | 467 | * An uninstall of a non administrative (current user) installation prompts to remove the Syncthing firewall rule if it exists (requires administrative permissions). 468 | 469 | * A silent uninstall of a non administrative (current user) installation does not remove the Syncthing firewall rule, and you must to remove it manually. It is recommended to remove the firewall rule _before_ performing a silent uninstall if uninstalling for the current user (see [Removing the Firewall Rule Manually](#removing-the-firewall-rule-manually)). 470 | 471 | * An uninstall of an administrative (all users) installation removes the Syncthing firewall rule automatically, without prompting. 472 | 473 | ### Removing the Firewall Rule Manually 474 | 475 | If you installed using non administrative installation mode and need to remove the Syncthing firewall rule manually, open a PowerShell or command prompt window and run the following command: 476 | 477 | cscript "C:\Users\username\AppData\Local\Programs\Syncthing\SyncthingFirewallRule.js" /remove 478 | 479 | (where `C:\Users\username\appData\Local\Programs\Syncthing` is the Syncthing installation folder; replace `username` with the correct username) 480 | 481 | ## Helper Tools 482 | 483 | Setup installs a set of helper tools to the installation folder to facilitate ease-of-use, depending on the [installation mode](#administrative-vs-non-administrative-installation-mode), as described in the following table. 484 | 485 | Tool | Installation Mode | Description 486 | ------ | ----------------- | ----------- 487 | `SetSyncthingConfig.js` | Both | Setup uses this script to create and/or configure the Syncthing configuration file (`config.xml`). 488 | `SyncthingFirewallRule.js` | Both | Adds, removes, and tests for the existence of a Windows Firewall rule for Syncthing (prompts for administrative permissions if required). 489 | `ErrInfo.exe` | Both | Used in scripts to get localized error message strings 490 | `SyncthingLogonTask.js` | Current user (non admin) | Adds or removes a scheduled task that runs the `StartSyncthing.js` script at logon. 491 | `stctl.exe` | Current user (non admin) | Helper program for starting and stopping Syncthing for the current user. 492 | `asmt.exe` | All users (admin) | Helper program for installing and/or resetting the service account and service configuration. 493 | `ServMan.exe` | All users (admin) | Helper program for starting and stopping the Syncthing service. 494 | `shawl.exe` | All users (admin) | Helper program for running Syncthing as a Windows service. 495 | 496 | ## Resetting the Service Account Password 497 | 498 | If you installed using administrative (all users) installation mode and want to reset the service account password, do the following: 499 | 500 | 1. Open a PowerShell or cmd.exe window as administrator 501 | 502 | 2. Change to the Syncthing installation folder; e.g. `cd "\Program Files\Syncthing"` 503 | 504 | 3. Run the following command: 505 | 506 | `.\asmt --reset --account=SyncthingServiceAcct --name=syncthing` 507 | 508 | This command will reset the service account's password to a long, random password and update the Syncthing service to start with the new password. 509 | 510 | > NOTE: If you changed the default service account username (not recommended), specify it after the `--account=` option. 511 | 512 | ## Finding the Syncthing Configuration Folder 513 | 514 | The location of the Syncthing configuration folder depends on whether you run Setup in non administrative (current user) or administrative (all users) or installation mode: 515 | 516 | * If you installed for the current user (the default), the Syncthing configuration folder is in the following location: 517 | 518 | _LocalAppData_`\Syncthing` 519 | 520 | where: _LocalAppData_ is the current user's local application data folder (e.g., `C:\Users\UserName\AppData\Local`) 521 | 522 | Administrative permissions are not required to access this folder. 523 | 524 | * If you installed for all users (i.e., you specified the `/allusers` parameter on Setup's command line), the Syncthing configuration folder is in the following location: 525 | 526 | _CommonAppData_`\Syncthing` 527 | 528 | where: _CommonAppData_ is the common application data folder (e.g., `C:\ProgramData`) 529 | 530 | Administrative permissions are required to access this folder. 531 | 532 | ## Uninstalling Syncthing 533 | 534 | You can uninstall Syncthing using the standard Windows application management list. 535 | 536 | If you installed Syncthing in non administrative installation mode (current user only), the uninstall process prompts to remove the Syncthing firewall rule if it exists (this requires administrative permissions). 537 | 538 | If you installed syncthing in administrative install mode, note that the uninstall process: 539 | 540 | * Removes the Syncthing firewall rule 541 | 542 | * Revokes the **Log on as a service** user right from the local service user account 543 | 544 | * Disables (but does not delete) the local service user account 545 | 546 | Regardless of whether you installed Syncthing in administrative or non administrative mode, the uninstall process does not remove any Syncthing configuration files. If you want to remove the Syncthing configuration folder, determine its location (see [Finding the Syncthing Configuration Folder](#finding-the-syncthing-configuration-folder)) and remove it after uninstalling. 547 | 548 | ## Silent Install and Uninstall 549 | 550 | Setup supports silent (hands-free) install and uninstall mode using the `/silent` command line parameter. 551 | 552 | * See [Setup Command Line Parameters](#setup-command-line-parameters) for information about Setup's command line parameters. 553 | 554 | * See the [Inno Setup documentation](https://jrsoftware.org/ishelp/index.php?topic=uninstcmdline) for information about the uninstall program's conmmand line parameters. 555 | 556 | ### Silent Non Administrative (Current User) Installation 557 | 558 | To perform an initial install (i.e., not a reinstall or upgrade) silently in non administrative (current user) installation mode, specify the `/silent` parameter on Setup's command line. (You can also include `/currentuser` on Setup's command line for clarity if desired, but this is not required as `/currentuser` is the default.) In this mode, Setup: 559 | 560 | * Does not install the Windows service 561 | 562 | * Does not create a firewall rule for Syncthing (this is because creating a firewall rule requires administrative permissions, which would cause a prompt that would prevent the silent installation from completing) 563 | 564 | * Starts Syncthing for the current user if a firewall rule for Syncthing already exists 565 | 566 | To ensure Syncthing works correctly after a non administrative (current user) silent installation, create the firewall rule manually (see [Creating the Firewall Rule Manually](#creating-the-firewall-rule-manually)) before starting Syncthing. 567 | 568 | ### Silent Administrative (All Users) Installation 569 | 570 | To perform a silent installation in administrative installation (all users) mode, you must specify both the `/allusers` and `/silent` parameters on Setup's command line. In this mode, Setup: 571 | 572 | * Installs the Windows service 573 | 574 | * Automatically creates a firewall rule for Syncthing 575 | 576 | * Starts the Syncthing service after installation completes 577 | 578 | > NOTE: You must specify `/allusers` if reinstalling in administrative (all users) installation mode. 579 | 580 | ### Silent Uninstall 581 | 582 | To uninstall silently, specify `/silent` on the uninstaller's command line (the uninstaller executable is located in the `uninstall` directory inside the Syncthing installation folder). 583 | 584 | If you installed Syncthing for the current user, you must remove the Syncthing firewall rule manually (see [Removing the Firewall Rule Manually](#removing-the-firewall-rule-manually)) before uninstalling silently. 585 | 586 | ## Reporting Problems 587 | 588 | If you encounter a problem with Setup or one of the helper tools, please inform the author by filing an issue on the Issues page: 589 | 590 | https://github.com/Bill-Stewart/SyncthingWindowsSetup/issues 591 | 592 | For Syncthing support (not related to Setup or the helper tools), please visit the Syncthing forum: 593 | 594 | https://forum.syncthing.net/ 595 | 596 | ## Acknowledgments 597 | 598 | Special thanks to the following: 599 | 600 | * Syncthing maintainers 601 | 602 | * mtkennerly for [shawl](https://github.com/mtkennerly/shawl) 603 | 604 | * Jordan Russell and Martijn Laan for [Inno Setup](https://www.jrsoftware.org/isinfo.php) 605 | 606 | * [Info-ZIP](https://infozip.sourceforge.net/) maintainers 607 | 608 | * [jq](https://jqlang.github.io/jq/) maintainers 609 | -------------------------------------------------------------------------------- /Syncthing.iss: -------------------------------------------------------------------------------- 1 | ; Syncthing.iss - Syncthing Windows Setup 2 | ; Written by Bill Stewart (bstewart AT iname.com) for Syncthing 3 | 4 | ; Windows Inno Setup installer for Syncthing (https://syncthing.net/) 5 | ; * see LICENSE for license 6 | ; * See README.md for documentation 7 | ; * See building.md for build/localization info 8 | 9 | #if Ver < EncodeVer(6,3,3,0) 10 | #error This script requires Inno Setup 6.3.3 or later 11 | #endif 12 | 13 | #define UninstallIfSetupVersionOlderThan "1.27.11" 14 | #define AppID "{1EEA2B6F-FD76-47D7-B74C-03E14CF043F9}" 15 | #define GitHubUserName "syncthing" 16 | #define GitHubProjectName "syncthing" 17 | #define GitHubVersionTagURLPattern "https://api.github.com/repos/%s/%s/releases/latest" 18 | #define GitHubDownloadURLPattern "https://github.com/%s/%s/releases/download/%s/%s" 19 | #define ZipFileNamePattern "syncthing-windows-%s-%s.zip" 20 | #define UnzipPattern "*/syncthing.exe */AUTHORS.txt */README.txt */LICENSE.txt" 21 | #define AppName "Syncthing" 22 | #define AppPublisher "Syncthing Foundation" 23 | #define AppURL "https://syncthing.net/" 24 | #define IniFileName "SetupVersion.ini" 25 | #define SetupVersion ReadIni(AddBackslash(SourcePath) + IniFileName, "Setup", "Version") 26 | #define ServiceName "syncthing" 27 | #define ServiceShutdownTimeout "10000" 28 | #define DefaultAutoUpgradeInterval "12" 29 | #define DefaultListenAddress "127.0.0.1" 30 | #define DefaultListenPort "8384" 31 | #define DefaultRelaysEnabled "true" 32 | #define DefaultServiceAccountUserName "SyncthingServiceAcct" 33 | #define ConfigurationPageName "ConfigurationPage" 34 | #define LicenseFileName "License.rtf" 35 | #define ScriptNameSetSyncthingConfig "SetSyncthingConfig.js" 36 | #define ScriptNameSyncthingFirewallRule "SyncthingFirewallRule.js" 37 | #define ScriptNameSyncthingLogonTask "SyncthingLogonTask.js" 38 | 39 | [Setup] 40 | AppId={{#AppID} 41 | AppName={#AppName} 42 | AppVerName={#AppName} 43 | AppPublisher={#AppPublisher} 44 | AppPublisherURL={#AppURL} 45 | AppSupportURL={#AppURL} 46 | AppUpdatesURL={#AppURL} 47 | MinVersion=10 48 | ArchitecturesInstallIn64BitMode=x64compatible 49 | CloseApplications=no 50 | CloseApplicationsFilter=*.exe 51 | RestartApplications=yes 52 | DefaultDirName={autopf}\{#AppName} 53 | DefaultGroupName={#AppName} 54 | DisableWelcomePage=yes 55 | AllowNoIcons=yes 56 | PrivilegesRequired=lowest 57 | PrivilegesRequiredOverridesAllowed=commandline 58 | OutputDir=. 59 | OutputBaseFilename=syncthing-windows-setup 60 | Compression=lzma2/max 61 | SolidCompression=yes 62 | LZMADictionarySize=131072 63 | LZMANumFastBytes=273 64 | LZMAUseSeparateProcess=yes 65 | UsePreviousTasks=yes 66 | WizardStyle=modern 67 | WizardSizePercent=120 68 | UninstallFilesDir={app}\uninstall 69 | UninstallDisplayIcon={app}\syncthing.ico 70 | UninstallDisplayName={code:GetUninstallDisplayName} 71 | VersionInfoProductName={#AppName} 72 | VersionInfoCompany={#AppPublisher} 73 | VersionInfoVersion={#SetupVersion} 74 | 75 | [Messages] 76 | SetupWindowTitle=Syncthing Windows Setup 77 | 78 | [Languages] 79 | Name: "en"; MessagesFile: "compiler:Default.isl,Messages-en.isl"; InfoBeforeFile: "en-README.rtf" 80 | 81 | ; See building.md file for localization details 82 | #define protected 83 | #define LocalizationFile AddBackslash(SourcePath) + "Localization.ini" 84 | #define NumLanguages 1 85 | #dim Languages[NumLanguages] 86 | #define Languages[0] "en" 87 | 88 | [Files] 89 | ; Preprocessor localization 90 | #define i 0 91 | #sub LocalizeFiles 92 | #define Language Languages[i] 93 | #define FileNameLicense ReadIni(LocalizationFile, Language, "LicenseFile") 94 | #define ScriptNameSetConfig ReadIni(LocalizationFile, Language, "ScriptNameSetSyncthingConfig") 95 | #define ScriptNameFirewallRule ReadIni(LocalizationFile, Language, "ScriptNameSyncthingFirewallRule") 96 | #define ScriptNameLogonTask ReadIni(LocalizationFile, Language, "ScriptNameSyncthingLogonTask") 97 | Source: "{#FileNameLicense}"; DestName: "{#LicenseFileName}"; flags: dontcopy 98 | Source: "{#ScriptNameFirewallRule}"; DestDir: "{app}"; DestName: "{#ScriptNameSyncthingFirewallRule}"; Languages: "{#Language}" 99 | Source: "{#ScriptNameSetConfig}"; DestDir: "{app}"; DestName: "{#ScriptNameSetSyncthingConfig}"; Languages: "{#Language}" 100 | Source: "{#ScriptNameLogonTask}"; DestDir: "{app}"; DestName: "{#ScriptNameSyncthingLogonTask}"; Languages: "{#language}"; Check: not IsAdminInstallMode() 101 | #endsub 102 | #for { i = 0; i < NumLanguages; i++ } LocalizeFiles 103 | 104 | ; Installer-only 105 | ; Support automatic uninstall of older versions 106 | Source: "UninsIS.dll"; Flags: dontcopy 107 | ; Process checking 108 | Source: "ProcessCheck.dll"; Flags: dontcopy 109 | ; Command-line JSON parser (get latest version tag from GitHub) 110 | Source: "jq.exe"; Flags: dontcopy 111 | ; unzip utility for extracting Syncthing after downloading 112 | Source: "unzip.exe"; Flags: dontcopy 113 | 114 | ; Setup version INI file 115 | Source: "{#IniFileName}"; DestDir: "{app}" 116 | 117 | ; shawl license 118 | Source: "shawl-license.txt"; DestDir: "{app}"; Check: IsAdminInstallMode() 119 | 120 | ; Icon 121 | Source: "syncthing.ico"; DestDir: "{app}" 122 | ; x86compatible binaries 123 | Source: "binaries\i386\asmt.exe"; DestDir: "{app}"; Check: (not IsX64Compatible()) and IsAdminInstallMode() 124 | Source: "binaries\i386\ErrInfo.exe"; DestDir: "{app}"; Check: (not IsX64Compatible()) and IsAdminInstallMode() 125 | Source: "binaries\i386\ServMan.exe"; DestDir: "{app}"; Check: (not IsX64Compatible()) and IsAdminInstallMode() 126 | Source: "binaries\i386\shawl.exe"; DestDir: "{app}"; Check: (not IsX64Compatible()) and IsAdminInstallMode() 127 | Source: "binaries\i386\stctl.exe"; DestDir: "{app}"; Check: (not IsX64Compatible()) and (not IsAdminInstallMode()) 128 | ; x64compatible binaries 129 | Source: "binaries\x86_64\asmt.exe"; DestDir: "{app}"; Check: IsX64Compatible() and IsAdminInstallMode(); Flags: solidbreak 130 | Source: "binaries\x86_64\ErrInfo.exe"; DestDir: "{app}"; Check: IsX64Compatible() and IsAdminInstallMode() 131 | Source: "binaries\x86_64\ServMan.exe"; DestDir: "{app}"; Check: IsX64Compatible() and IsAdminInstallMode() 132 | Source: "binaries\x86_64\shawl.exe"; DestDir: "{app}"; Check: IsX64Compatible() and IsAdminInstallMode() 133 | Source: "binaries\x86_64\stctl.exe"; DestDir: "{app}"; Check: IsX64Compatible() and (not IsAdminInstallMode()) 134 | 135 | [Dirs] 136 | Name: "{autoappdata}\{#AppName}"; Attribs: notcontentindexed; Check: IsAdminInstallMode() 137 | 138 | ; When to use cscript.exe vs. wscript.exe: 139 | ; * Use cscript.exe for hidden scripts (so error doesn't block execution) 140 | ; * Use wscript.exe for interactive scripts 141 | 142 | [Icons] 143 | ; Non-admin and admin icons 144 | Name: "{group}\{cm:ShortcutNameConfigurationPage}"; \ 145 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 146 | Comment: "{cm:ShortcutNameConfigurationPageComment}"; \ 147 | IconFilename: "{app}\syncthing.ico" 148 | Name: "{autodesktop}\{cm:ShortcutNameConfigurationPage}"; \ 149 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 150 | Comment: "{cm:ShortcutNameConfigurationPageComment}"; \ 151 | IconFilename: "{app}\syncthing.ico"; \ 152 | Tasks: desktopicon 153 | ; Non-admin icons 154 | Name: "{group}\{cm:ShortcutNameStartSyncthing}"; \ 155 | Filename: "{app}\stctl.exe"; \ 156 | Parameters: "--start"; \ 157 | Comment: "{cm:ShortcutNameStartSyncthingComment}"; \ 158 | Check: not IsAdminInstallMode() 159 | Name: "{group}\{cm:ShortcutNameStopSyncthing}"; \ 160 | Filename: "{app}\stctl.exe"; \ 161 | Parameters: "--stop"; \ 162 | Comment: "{cm:ShortcutNameStopSyncthingComment}"; \ 163 | Check: not IsAdminInstallMode() 164 | 165 | [INI] 166 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 167 | Section: "InternetShortcut"; \ 168 | Key: "URL"; \ 169 | String: "https://{code:GetListenAddress}:{code:GetListenPort}" 170 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 171 | Section: "InternetShortcut"; \ 172 | Key: "IconFile"; \ 173 | String: "{app}\syncthing.ico" 174 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 175 | Section: "InternetShortcut"; \ 176 | Key: "IconIndex"; \ 177 | String: "0" 178 | 179 | [Tasks] 180 | ; Admin 181 | Name: startatboot; \ 182 | Description: "{cm:TasksStartAtBoot}"; \ 183 | Check: IsAdminInstallMode() 184 | Name: startserviceafterinstall; \ 185 | Description: "{cm:TasksStartServiceAfterInstall}"; \ 186 | Check: IsAdminInstallMode() 187 | ; Non-admin 188 | Name: startatlogon; \ 189 | Description: "{cm:TasksStartAtLogon}"; \ 190 | Check: not IsAdminInstallMode(); \ 191 | Flags: checkablealone 192 | Name: startatlogon\acpoweronly; \ 193 | Description: "{cm:TasksStartAtLogon_ACPowerOnly}"; \ 194 | Check: not IsAdminInstallMode(); \ 195 | Flags: dontinheritcheck unchecked 196 | Name: startafterinstall; \ 197 | Description: "{cm:TasksStartAfterInstall}"; \ 198 | Check: not IsAdminInstallMode() 199 | Name: desktopicon; \ 200 | Description: "{cm:TasksCreateDesktopIcon}"; \ 201 | Flags: unchecked 202 | 203 | [Run] 204 | ; Admin: Add firewall rule silently 205 | Filename: "{sys}\cscript.exe"; \ 206 | Parameters: """{app}\{#ScriptNameSyncthingFirewallRule}"" /create /elevated /silent"; \ 207 | Flags: runhidden; \ 208 | StatusMsg: "{cm:RunStatusMsg}"; \ 209 | Check: IsAdminInstallMode() 210 | ; Non-admin: Prompt to add firewall rule 211 | Filename: "{sys}\wscript.exe"; \ 212 | Parameters: """{app}\{#ScriptNameSyncthingFirewallRule}"" /create"; \ 213 | StatusMsg: "{cm:RunStatusMsg}"; \ 214 | Check: (not IsAdminInstallMode()) and (not FirewallRuleExists()) and (not WizardSilent()) 215 | ; postinstall 216 | Filename: "{app}\{#ConfigurationPageName}.url"; \ 217 | Description: "{cm:RunPostInstallOpenConfigPage}"; \ 218 | Flags: shellexec postinstall skipifsilent; \ 219 | Check: ShowPostInstallCheckbox() and IsSyncthingRunning() 220 | 221 | [UninstallRun] 222 | ; Admin: remove firewall rule 223 | Filename: "{sys}\cscript.exe"; \ 224 | Parameters: """{app}\{#ScriptNameSyncthingFirewallRule}"" /remove /elevated /silent"; \ 225 | Flags: runhidden; \ 226 | RunOnceId: removefwrule; \ 227 | Check: IsAdminInstallMode() 228 | ; Non-admin: remove logon task 229 | Filename: "{sys}\cscript.exe"; \ 230 | Parameters: """{app}\{#ScriptNameSyncthingLogonTask}"" /remove /silent"; \ 231 | Flags: runhidden; \ 232 | RunOnceId: removelogontask; \ 233 | Check: not IsAdminInstallMode() 234 | 235 | [UninstallDelete] 236 | Type: files; Name: "{app}\{#ConfigurationPageName}.url" 237 | Type: files; Name: "{app}\syncthing.exe.old" 238 | Type: files; Name: "{app}\syncthing.exe" 239 | Type: files; Name: "{app}\AUTHORS.txt" 240 | Type: files; Name: "{app}\README.txt" 241 | Type: files; Name: "{app}\LICENSE.txt" 242 | 243 | [Code] 244 | 245 | // General notes about online vs. offline installation: 246 | // * LatestVersionTag gets set if we connected to github.com, downloaded latest 247 | // version JSON file, and retrieved the latest version tag using jq.exe 248 | // * LatestVersionTag = '' if we couldn't get to github.com 249 | // * Therefore, LatestVersionTag = '' means offline install 250 | // * If offline (LatestVersionTag empty), ZipFilePath gets set by: 251 | // a. /zipfilepath= command line parameter, or 252 | // b. Wizard file selection page 253 | // * If user specifies /zipfilepath, don't attempt to get latest version JSON 254 | // * If online (LatestVersionTag not empty), ZipFilePath gets set in 255 | // NextButtonClick event 256 | // * Install only proceeds if zip file tests ok (i.e., unzip -t returns 0) 257 | 258 | const 259 | ERROR_MORE_DATA = 234; 260 | ERROR_SERVICE_ALREADY_RUNNING = 1056; 261 | ERROR_SERVICE_NOT_ACTIVE = 1062; 262 | 263 | type 264 | TInstallType = (InstallTypeNotInstalled, InstallTypeAdmin, InstallTypeNonAdmin); 265 | 266 | // Global variables 267 | var 268 | OutputMsgMemoPage0: TOutputMsgMemoWizardPage; 269 | ConfigPage0: TInputQueryWizardPage; 270 | FilePage0: TInputFileWizardPage; 271 | DownloadPage0: TDownloadWizardPage; 272 | // Configuration page values 273 | AutoUpgradeInterval, ListenAddress, ListenPort, RelaysEnabled: string; 274 | ServiceAccountUserName, ExecOutputFirstLine, ZipFilePath, LatestVersionTag: string; 275 | 276 | // Windows API functions 277 | function GetUserNameExW(NameFormat: Integer; lpNameBuffer: string; var nSize: DWORD): Boolean; 278 | external 'GetUserNameExW@secur32.dll stdcall setuponly'; 279 | 280 | // UninsIS.dll functions 281 | function DLLCompareVersionStrings(Version1, Version2: string): Integer; 282 | external 'CompareVersionStrings@files:UninsIS.dll stdcall setuponly'; 283 | function DLLIsISPackageInstalled(AppId: string; Is64BitInstallMode, IsAdminInstallMode: DWORD): DWORD; 284 | external 'IsISPackageInstalled@files:UninsIS.dll stdcall setuponly'; 285 | function DLLUninstallISPackage(AppId: string; Is64BitInstallMode, IsAdminInstallMode: DWORD): DWORD; 286 | external 'UninstallISPackage@files:UninsIS.dll stdcall setuponly'; 287 | 288 | // ProcessCheck.dll functions 289 | function DLLFindProcess(PathName: string; var Found: DWORD): DWORD; 290 | external 'FindProcess@files:ProcessCheck.dll stdcall setuponly'; 291 | 292 | function GetFullUserName(): string; 293 | var 294 | NumChars: DWORD; 295 | OutStr: string; 296 | begin 297 | result := ''; 298 | try 299 | NumChars := 0; 300 | // NameFormat = 2: NameSamCompatible (i.e., authority\username) 301 | // First call: GetUserNameExW should return false and DLLGetLastError() 302 | // should return ERROR_MORE_DATA (234); NumChars will contain # chars 303 | // needed, including null terminator 304 | if (not GetUserNameExW(2, '', NumChars)) and (DLLGetLastError() = ERROR_MORE_DATA) then 305 | begin 306 | SetLength(OutStr, NumChars); 307 | if GetUserNameExW(2, OutStr, NumChars) then 308 | // Omit null terminator from result 309 | result := Copy(OutStr, 1, NumChars); 310 | end; 311 | except 312 | end; 313 | end; 314 | 315 | function IsSyncthingRunning(): Boolean; 316 | var 317 | PathName: string; 318 | Found: DWORD; 319 | begin 320 | Sleep(500); 321 | result := false; 322 | PathName := ExpandConstant('{app}\syncthing.exe'); 323 | if DLLFindProcess(PathName, Found) = 0 then 324 | begin 325 | result := Found = 1; 326 | if result then 327 | Log(FmtMessage(CustomMessage('ProcessCheckSucceededRunning'), [PathName])) 328 | else 329 | Log(FmtMessage(CustomMessage('ProcessCheckSucceededNotRunning'), [PathName])); 330 | end 331 | else 332 | Log(CustomMessage('ProcessCheckFailed')); 333 | end; 334 | 335 | // UninsIS.dll - Returns installation type 336 | function IsISPackageInstalled(): TInstallType; 337 | begin 338 | if DLLIsISPackageInstalled('{#AppID}', // AppId 339 | DWORD(Is64BitInstallMode()), // Is64BitInstallMode 340 | 1) = 1 then // IsAdminInstallMode 341 | begin 342 | result := InstallTypeAdmin; 343 | Log(CustomMessage('InstallTypeAdmin')); 344 | end 345 | else if DLLIsIsPackageInstalled('{#AppID}', // AppId 346 | DWORD(Is64BitInstallMode()), // Is64BitInstallMode 347 | 0) = 1 then // IsAdminInstallMode 348 | begin 349 | result := InstallTypeNonAdmin; 350 | Log(CustomMessage('InstallTypeNonAdmin')); 351 | end 352 | else 353 | begin 354 | result := InstallTypeNotInstalled; 355 | Log(CustomMessage('InstallTypeNotInstalled')); 356 | end; 357 | end; 358 | 359 | // UninsIS.dll - Returns: 360 | // < 0 if Version1 < Version2 361 | // 0 if Version1 = Version2 362 | // > 0 if Version1 > Version2 363 | function CompareVersionStrings(const Version1, Version2: string): Integer; 364 | begin 365 | result := DLLCompareVersionStrings(Version1, Version2); 366 | end; 367 | 368 | // UninsIS.dll - Returns 0 for success, non-zero for failure 369 | function UninstallISPackage(): DWORD; 370 | begin 371 | result := DLLUninstallISPackage('{#AppID}', // AppId 372 | DWORD(Is64BitInstallMode()), // Is64BitInstallMode 373 | DWORD(IsAdminInstallMode())); // IsAdminInstallMode 374 | end; 375 | 376 | function ParamStrExists(const Param: string): Boolean; 377 | var 378 | I: Integer; 379 | begin 380 | result := false; 381 | for I := 1 to ParamCount do 382 | begin 383 | result := CompareText(Param, ParamStr(I)) = 0; 384 | if result then 385 | exit; 386 | end; 387 | end; 388 | 389 | function ShowPostInstallCheckbox(): Boolean; 390 | begin 391 | result := not ParamStrExists('/noconfigpage'); 392 | end; 393 | 394 | function IsDomainController(): Boolean; 395 | var 396 | VersionInfo: TWindowsVersion; 397 | begin 398 | GetWindowsVersionEx(VersionInfo); 399 | result := VersionInfo.ProductType = VER_NT_DOMAIN_CONTROLLER; 400 | end; 401 | 402 | function IsWshJsScriptRegistrationValid(): Boolean; 403 | var 404 | Value: string; 405 | begin 406 | result := RegQueryStringValue(HKEY_CLASSES_ROOT, '.js', '', Value); 407 | if result then 408 | result := SameText(Value, 'JSFile'); 409 | end; 410 | 411 | procedure OnExecAndLogOutput(const S: String; const Error, FirstLine: Boolean); 412 | begin 413 | if (not Error) and (ExecOutputFirstLine = '') and (Trim(S) <> '') then 414 | ExecOutputFirstLine := S; // Store first line of non-empty output 415 | end; 416 | 417 | function ExecEx(const FileName, Params: string; const Hide: Boolean): Integer; 418 | var 419 | ShowCmd: Integer; 420 | OK: Boolean; 421 | begin 422 | if Hide then 423 | ShowCmd := SW_HIDE 424 | else 425 | ShowCmd := SW_SHOWNORMAL; 426 | OK := ExecAndLogOutput(FileName, // Filename 427 | Params, // Params 428 | '', // WorkingDir 429 | ShowCmd, // ShowCmd 430 | ewWaitUntilTerminated, // TExecWait 431 | result, // ResultCode 432 | @OnExecAndLogOutput); // TOnLog 433 | Log(Format('ExecEx: "%s" %s', [FileName, Params])); 434 | if OK then 435 | Log(Format('ExecEx exit code: %s', [IntToStr(result)])) 436 | else 437 | Log(Format('ExecEx failed: %s (%s)', [SysErrorMessage(result), IntToStr(result)])); 438 | end; 439 | 440 | function TestZipFile(const ZipFilePath: string): Boolean; 441 | begin 442 | result := ExecEx(ExpandConstant('{tmp}\unzip.exe'), 443 | ExpandConstant(Format('-t "%s" {#UnzipPattern}', [ZipFilePath])), true) = 0; 444 | end; 445 | 446 | function OnDownloadProgress(const Url, Filename: string; const Progress, ProgressMax: Int64): Boolean; 447 | begin 448 | result := true; 449 | if Progress = ProgressMax then 450 | Log(CustomMessage('DownloadFileSucceeded')); 451 | end; 452 | 453 | function DownloadFile(const URL, LocalFileName: string): Boolean; 454 | var 455 | BytesDownloaded: Int64; 456 | begin 457 | result := false; 458 | try 459 | BytesDownloaded := DownloadTemporaryFile(URL, LocalFileName, '', @OnDownloadProgress); 460 | result := BytesDownloaded > 0; 461 | except 462 | end; 463 | end; 464 | 465 | function GetLatestVersionJsonFilePath(): string; 466 | var 467 | URL, UniqueFilePath: string; 468 | begin 469 | result := ''; 470 | URL := Format('{#GitHubVersionTagURLPattern}', ['{#GitHubUserName}', '{#GitHubProjectName}']); 471 | UniqueFilePath := GenerateUniqueName(ExpandConstant('{tmp}'), '.json'); 472 | if DownloadFile(URL, ExtractFileName(UniqueFilePath)) then 473 | result := UniqueFilePath; 474 | end; 475 | 476 | procedure GetLatestVersionTag(); 477 | var 478 | JsonFilePath: string; 479 | begin 480 | if LatestVersionTag <> '' then 481 | exit; 482 | JsonFilePath := GetLatestVersionJsonFilePath(); 483 | if JsonFilePath = '' then 484 | exit; 485 | if ExecEx(ExpandConstant('{tmp}\jq.exe'), '-r .name "' + JsonFilePath + '"', true) = 0 then 486 | begin 487 | LatestVersionTag := ExecOutputFirstLine; 488 | Log('Latest version tag: ' + LatestVersionTag); 489 | end 490 | else 491 | Log('Failed to get latest version tag'); 492 | end; 493 | 494 | function InitializeSetup(): Boolean; 495 | var 496 | Msg: string; 497 | begin 498 | if IsAdminInstallMode() then 499 | begin 500 | ServiceAccountUserName := GetPreviousData('ServiceAccountUserName', 501 | Trim(ExpandConstant('{param:serviceaccountusername|{#DefaultServiceAccountUserName}}'))); 502 | result := not IsDomainController(); 503 | if not result then 504 | begin 505 | Msg := CustomMessage('InitializeSetupError0'); 506 | Log(Msg); 507 | if not WizardSilent() then 508 | MsgBox(Msg, mbCriticalError, MB_OK); 509 | exit; 510 | end; 511 | end; 512 | result := IsWshJsScriptRegistrationValid(); 513 | if not result then 514 | begin 515 | Msg := CustomMessage('InitializeSetupError1'); 516 | Log(Msg); 517 | if not WizardSilent() then 518 | MsgBox(Msg, mbCriticalError, MB_OK); 519 | exit; 520 | end; 521 | // /currentuser is the default, so abort Setup if admin install detected 522 | // and tell user to restart Setup using /allusers option 523 | if (not IsAdminInstallMode()) and (IsISPackageInstalled() = InstallTypeAdmin) and (not ParamStrExists('/allowcurrentuser')) then 524 | begin 525 | result := false; 526 | Msg := CustomMessage('InitializeSetupError2'); 527 | Log(Msg); 528 | if not WizardSilent() then 529 | MsgBox(Msg, mbCriticalError, MB_OK); 530 | exit; 531 | end; 532 | ExecOutputFirstLine := ''; 533 | // Custom command line parameters 534 | AutoUpgradeInterval := GetPreviousData('AutoUpgradeInterval', 535 | Trim(ExpandConstant('{param:autoupgradeinterval|{#DefaultAutoUpgradeInterval}}'))); 536 | ListenAddress := GetPreviousData('ListenAddress', 537 | Trim(ExpandConstant('{param:listenaddress|{#DefaultListenAddress}}'))); 538 | ListenPort := GetPreviousData('ListenPort', 539 | Trim(ExpandConstant('{param:listenport|{#DefaultListenPort}}'))); 540 | RelaysEnabled := GetPreviousData('RelaysEnabled', 541 | Trim(ExpandConstant('{param:relaysenabled|{#DefaultRelaysEnabled}}'))); 542 | ExtractTemporaryFile('unzip.exe'); 543 | ZipFilePath := Trim(ExpandConstant('{param:zipfilepath}')); 544 | if ZipFilePath = '' then 545 | begin 546 | // Zip file path not specified on command line; try to get it dynamically 547 | ExtractTemporaryFile('jq.exe'); 548 | GetLatestVersionTag(); 549 | if LatestVersionTag = '' then 550 | begin 551 | Msg := CustomMessage('InitializeSetupWarning0'); 552 | Log(Msg); 553 | end; 554 | end 555 | else 556 | begin 557 | // Assume installer directory if no path specifed with zip file name 558 | if Pos('\', ZipFilePath) = 0 then 559 | ZipFilePath := ExpandConstant('{src}\') + ZipFilePath; 560 | end; 561 | end; 562 | 563 | procedure InitializeWizard(); 564 | var 565 | LicenseOK: Boolean; 566 | PageID: Integer; 567 | LicenseFileText: AnsiString; 568 | begin 569 | // Custom memo page(s) 570 | ExtractTemporaryFile('{#LicenseFileName}'); 571 | LicenseOK := LoadStringFromFile(ExpandConstant('{tmp}\{#LicenseFileName}'), LicenseFileText); 572 | if LicenseOK then 573 | begin 574 | OutputMsgMemoPage0 := CreateOutputMsgMemoPage(wpInfoBefore, 575 | CustomMessage('MemoPage0Caption'), 576 | CustomMessage('MemoPage0Description'), 577 | CustomMessage('MemoPage0SubCaption'), 578 | LicenseFileText); 579 | PageID := OutputMsgMemoPage0.ID; 580 | end 581 | else 582 | PageID := wpInfoBefore; 583 | // Custom file page(s) 584 | FilePage0 := CreateInputFilePage(PageID, 585 | CustomMessage('FilePage0Caption'), 586 | CustomMessage('FilePage0Description'), 587 | CustomMessage('FilePage0SubCaption')); 588 | FilePage0.Add(CustomMessage('FilePage0Prompt'), CustomMessage('FilePage0Filter'), '.zip'); 589 | if ZipFilePath <> '' then 590 | FilePage0.Values[0] := ZipFilePath; 591 | // Custom configuration page(s) 592 | ConfigPage0 := CreateInputQueryPage(wpSelectProgramGroup, 593 | CustomMessage('ConfigPage0Caption'), 594 | CustomMessage('ConfigPage0Description'), 595 | CustomMessage('ConfigPage0SubCaption')); 596 | ConfigPage0.Add(FmtMessage(CustomMessage('ConfigPage0Item0'), ['{#DefaultAutoUpgradeInterval}']), false); 597 | ConfigPage0.Add(FmtMessage(CustomMessage('ConfigPage0Item1'), ['{#DefaultListenAddress}']), false); 598 | ConfigPage0.Add(FmtMessage(CustomMessage('ConfigPage0Item2'), ['{#DefaultListenPort}']), false); 599 | ConfigPage0.Add(FmtMessage(CustomMessage('ConfigPage0Item3'), ['{#DefaultRelaysEnabled}']), false); 600 | ConfigPage0.Values[0] := AutoUpgradeInterval; 601 | ConfigPage0.Values[1] := ListenAddress; 602 | ConfigPage0.Values[2] := ListenPort; 603 | ConfigPage0.Values[3] := RelaysEnabled; 604 | // Custom download page(s) 605 | DownloadPage0 := CreateDownloadPage(SetupMessage(msgWizardPreparing), 606 | SetupMessage(msgPreparingDesc), @OnDownloadProgress); 607 | DownloadPage0.ShowBaseNameInsteadOfUrl := true; 608 | end; 609 | 610 | function InitializeUninstall(): Boolean; 611 | begin 612 | result := true; 613 | if IsAdminInstallMode() then 614 | begin 615 | ServiceAccountUserName := GetPreviousData('ServiceAccountUserName', '{#DefaultServiceAccountUserName}'); 616 | end; 617 | end; 618 | 619 | procedure RegisterPreviousData(PreviousDataKey: Integer); 620 | begin 621 | SetPreviousData(PreviousDataKey, 'AutoUpgradeInterval', AutoUpgradeInterval); 622 | SetPreviousData(PreviousDataKey, 'ListenAddress', ListenAddress); 623 | SetPreviousData(PreviousDataKey, 'ListenPort', ListenPort); 624 | SetPreviousData(PreviousDataKey, 'RelaysEnabled', RelaysEnabled); 625 | if IsAdminInstallMode() then 626 | begin 627 | SetPreviousData(PreviousDataKey, 'ServiceAccountUserName', ServiceAccountUserName); 628 | end; 629 | end; 630 | 631 | function GetDownloadFileName(): string; 632 | var 633 | ProcArch: string; 634 | begin 635 | result := ''; 636 | case ProcessorArchitecture() of 637 | paX86, paUnknown: ProcArch := '386'; 638 | paX64: ProcArch := 'amd64'; 639 | paArm64: ProcArch := 'arm64'; 640 | else 641 | exit; 642 | end; 643 | result := Format('{#ZipfileNamePattern}', [ProcArch, LatestVersionTag]); 644 | end; 645 | 646 | function GetDownloadURL(const DownloadFileName: string): string; 647 | begin 648 | result := ''; 649 | if LatestVersionTag = '' then 650 | exit; 651 | result := Format('{#GitHubDownloadURLPattern}', ['{#GitHubUserName}', 652 | '{#GitHubProjectName}', LatestVersionTag, DownloadFileName]); 653 | end; 654 | 655 | function ShouldSkipPage(PageID: Integer): Boolean; 656 | begin 657 | result := false; 658 | if PageID = FilePage0.ID then 659 | begin 660 | // Skip zip file page if we were able to get latest version tag 661 | result := LatestVersionTag <> ''; 662 | end; 663 | end; 664 | 665 | function NextButtonClick(CurPageID: Integer): Boolean; 666 | var 667 | UpgradeInterval, Port: Integer; 668 | Relays, DownloadFileName, DownloadURL, Msg: string; 669 | begin 670 | result := true; 671 | if CurPageID = FilePage0.ID then 672 | begin 673 | result := Trim(FilePage0.Values[0]) <> ''; 674 | if not result then 675 | begin 676 | Log(CustomMessage('FilePage0Item0Empty')); 677 | if not WizardSilent() then 678 | MsgBox(CustomMessage('FilePage0Item0Empty'), mbError, MB_OK); 679 | WizardForm.ActiveControl := FilePage0.Edits[0]; 680 | FilePage0.Values[0] := ''; 681 | exit; 682 | end; 683 | result := FileExists(FilePage0.Values[0]); 684 | if not result then 685 | begin 686 | Log(CustomMessage('ZipFilePathNotFound')); 687 | if not WizardSilent() then 688 | MsgBox(CustomMessage('ZipFilePathNotFound'), mbError, MB_OK); 689 | WizardForm.ActiveControl := FilePage0.Edits[0]; 690 | FilePage0.Edits[0].SelectAll(); 691 | exit; 692 | end; 693 | result := TestZipFile(FilePage0.Values[0]); 694 | if not result then 695 | begin 696 | Log(CustomMessage('ZipFileNotValid')); 697 | if not WizardSilent() then 698 | MsgBox(CustomMessage('ZipFileNotValid'), mbError, MB_OK); 699 | FilePage0.Edits[0].SelectAll(); 700 | exit; 701 | end; 702 | // Update global based on page 703 | ZipFilePath := Trim(FilePage0.Values[0]); 704 | end 705 | else if CurPageID = ConfigPage0.ID then 706 | begin 707 | //------------------------------------------------------------------------- 708 | // 0 - Validate auto upgrade interval (>= 0 and <= 65535) 709 | UpgradeInterval := StrToIntDef(Trim(ConfigPage0.Values[0]), -1); 710 | result := (UpgradeInterval >= 0) and (UpgradeInterval <= 65535); 711 | if not result then 712 | begin 713 | Log(CustomMessage('ConfigPage0Item0NotValid')); 714 | if not WizardSilent() then 715 | MsgBox(CustomMessage('ConfigPage0Item0NotValid'), mbError, MB_OK); 716 | WizardForm.ActiveControl := ConfigPage0.Edits[0]; 717 | ConfigPage0.Values[0] := '{#DefaultAutoUpgradeInterval}'; 718 | ConfigPage0.Edits[0].SelectAll(); 719 | exit; 720 | end; 721 | // Update global based on page 722 | AutoUpgradeInterval := Trim(ConfigPage0.Values[0]); 723 | //------------------------------------------------------------------------- 724 | // 1 - Validate listen address (not empty) 725 | result := Trim(ConfigPage0.Values[1]) <> ''; 726 | if not result then 727 | begin 728 | Log(CustomMessage('ConfigPage0Item1Empty')); 729 | if not WizardSilent() then 730 | MsgBox(CustomMessage('ConfigPage0Item1Empty'), mbError, MB_OK); 731 | WizardForm.ActiveControl := ConfigPage0.Edits[1]; 732 | ConfigPage0.Values[1] := '{#DefaultListenAddress}'; 733 | ConfigPage0.Edits[1].SelectAll(); 734 | exit; 735 | end; 736 | // Update global based on page 737 | ListenAddress := Trim(ConfigPage0.Values[1]); 738 | //------------------------------------------------------------------------- 739 | // 2 - Validate listen port (>= 1024 and <= 65535) 740 | Port := StrToIntDef(Trim(ConfigPage0.Values[2]), -1); 741 | result := (Port >= 1024) and (Port <= 65535); 742 | if not result then 743 | begin 744 | Log(CustomMessage('ConfigPage0Item2NotValid')); 745 | if not WizardSilent() then 746 | MsgBox(CustomMessage('ConfigPage0Item2NotValid'), mbError, MB_OK); 747 | WizardForm.ActiveControl := ConfigPage0.Edits[2]; 748 | ConfigPage0.Values[2] := '{#DefaultListenPort}'; 749 | ConfigPage0.Edits[2].SelectAll(); 750 | exit; 751 | end; 752 | // Update global based on page 753 | ListenPort := Trim(ConfigPage0.Values[2]); 754 | //------------------------------------------------------------------------- 755 | // 3 - Validate relays enabled ('true' or 'false') 756 | Relays := Lowercase(Trim(ConfigPage0.Values[3])); 757 | result := (Relays = 'false') or (Relays = 'true'); 758 | if not result then 759 | begin 760 | Log(CustomMessage('ConfigPage0Item3NotValid')); 761 | if not WizardSilent() then 762 | MsgBox(CustomMessage('ConfigPage0Item3NotValid'), mbError, MB_OK); 763 | WizardForm.ActiveControl := ConfigPage0.Edits[3]; 764 | ConfigPage0.Values[3] := '{#DefaultRelaysEnabled}'; 765 | ConfigPage0.Edits[3].SelectAll(); 766 | exit; 767 | end; 768 | // Update global based on page 769 | RelaysEnabled := Relays; 770 | end 771 | else if CurPageID = wpReady then 772 | begin 773 | // No need to download if we already have zip file path 774 | if ZipFilePath <> '' then 775 | exit; 776 | DownloadFileName := GetDownloadFileName(); 777 | DownloadURL := GetDownloadURL(DownloadFileName); 778 | DownloadPage0.Clear(); 779 | DownloadPage0.Add(DownloadURL, DownloadFileName, ''); 780 | DownloadPage0.Show(); 781 | try 782 | try 783 | DownloadPage0.Download(); 784 | except 785 | result := false; 786 | if DownloadPage0.AbortedByUser then 787 | Msg := CustomMessage('DownloadPageAbortedByUser') 788 | else 789 | Msg := AddPeriod(GetExceptionMessage); 790 | if not WizardSilent() then 791 | Msgbox(Msg, mbCriticalError, MB_OK) 792 | else 793 | Log(Msg); 794 | end; 795 | finally 796 | DownloadPage0.Hide(); 797 | end; 798 | if result then 799 | begin 800 | ZipFilePath := ExpandConstant(Format('{tmp}\%s', [DownloadFileName])); 801 | result := TestZipFile(ZipFilePath); 802 | if not result then 803 | begin 804 | ZipFilePath := ''; 805 | Msg := CustomMessage('ZipFileNotValid'); 806 | Log(Msg); 807 | if not WizardSilent() then 808 | MsgBox(Msg, mbCriticalError, MB_OK); 809 | exit; 810 | end; 811 | end; 812 | end; 813 | end; 814 | 815 | function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, 816 | MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: string): string; 817 | var 818 | Info: string; 819 | begin 820 | Info := ''; 821 | if LatestVersionTag = '' then 822 | begin 823 | Info := Info + CustomMessage('ReadyMemoZipFileInfo') + NewLine + Space; 824 | Info := Info + ZipFilePath; 825 | end; 826 | // Show installation mode 827 | if Info <> '' then 828 | Info := Info + NewLine + NewLine; 829 | Info := Info + CustomMessage('ReadyMemoInstallSettings') + NewLine + Space; 830 | if LatestVersionTag <> '' then 831 | Info := Info + FmtMessage(CustomMessage('ReadyMemoInstallOnline'), [LatestVersionTag]) 832 | else 833 | Info := Info + CustomMessage('ReadyMemoInstallOffline'); 834 | Info := Info + NewLine + Space; 835 | if IsAdminInstallMode() then 836 | Info := Info + CustomMessage('ReadyMemoInstallAdmin') + NewLine + Space 837 | + FmtMessage(CustomMessage('ReadyMemoInstallAdminServiceAccountUserName'), [ServiceAccountUserName]) 838 | else 839 | Info := Info + FmtMessage(CustomMessage('ReadyMemoInstallCurrentUser'), [GetFullUserName()]); 840 | if MemoUserInfoInfo <> '' then 841 | begin 842 | if Info <> '' then 843 | Info := Info + NewLine + NewLine; 844 | Info := Info + MemoUserInfoInfo; 845 | end; 846 | if MemoDirInfo <> '' then 847 | begin 848 | if Info <> '' then 849 | Info := Info + NewLine + NewLine; 850 | Info := Info + MemoDirInfo; 851 | end; 852 | if MemoTypeInfo <> '' then 853 | begin 854 | if Info <> '' then 855 | Info := Info + NewLine + NewLine; 856 | Info := Info + MemoTypeInfo; 857 | end; 858 | if MemoComponentsInfo <> '' then 859 | begin 860 | if Info <> '' then 861 | Info := Info + NewLine + NewLine; 862 | Info := Info + MemoComponentsInfo; 863 | end; 864 | if MemoGroupInfo <> '' then 865 | begin 866 | if Info <> '' then 867 | Info := Info + NewLine + NewLine; 868 | Info := Info + MemoGroupInfo; 869 | end; 870 | if Info <> '' then 871 | Info := Info + NewLine + NewLine; 872 | Info := Info + CustomMessage('ReadyMemoConfigInfo') + NewLine + Space; 873 | if StrToInt(AutoUpgradeInterval) <> 0 then 874 | Info := Info + FmtMessage(CustomMessage('ReadyMemoConfigItem0Enabled'), [AutoUpgradeInterval]) 875 | else 876 | Info := Info + CustomMessage('ReadyMemoConfigItem0Disabled'); 877 | Info := Info + NewLine; 878 | Info := Info + Space + CustomMessage('ReadyMemoConfigItem1') + ' ' + ListenAddress + NewLine 879 | + Space + CustomMessage('ReadyMemoConfigItem2') + ' ' + ListenPort; 880 | Info := Info + NewLine; 881 | if RelaysEnabled = 'false' then 882 | Info := Info + Space + CustomMessage('ReadyMemoConfigItem3Disabled') 883 | else 884 | Info := Info + Space + CustomMessage('ReadyMemoConfigItem3Enabled'); 885 | if MemoTasksInfo <> '' then 886 | begin 887 | if Info <> '' then 888 | Info := Info + NewLine + NewLine; 889 | Info := Info + MemoTasksInfo; 890 | end; 891 | result := Info; 892 | end; 893 | 894 | // Param parameter is required 895 | function GetListenAddress(Param: string): string; 896 | begin 897 | if (Trim(ListenAddress) = '0.0.0.0') or (Trim(ListenAddress) = '::') then 898 | result := '127.0.0.1' 899 | else 900 | result := ListenAddress; 901 | end; 902 | 903 | // Param parameter is required 904 | function GetListenPort(Param: string): string; 905 | begin 906 | result := ListenPort; 907 | end; 908 | 909 | // Param parameter is required 910 | function GetUninstallDisplayName(Param: string): string; 911 | begin 912 | result := ExpandConstant('{#AppName} '); 913 | if not IsAdminInstallMode() then 914 | result := result + CustomMessage('UninstallDisplayNamePerUserSuffix') 915 | else 916 | result := result + CustomMessage('UninstallDisplayNameServiceSuffix'); 917 | end; 918 | 919 | function ServiceExists(): Boolean; 920 | var 921 | FileName, Params: string; 922 | begin 923 | FileName := ExpandConstant('{app}\ServMan.exe'); 924 | Params := '--exists "{#ServiceName}"'; 925 | result := ExecEx(FileName, Params, true) = 0; 926 | end; 927 | 928 | function ServiceRunning(): Boolean; 929 | var 930 | FileName, Params: string; 931 | begin 932 | FileName := ExpandConstant('{app}\ServMan.exe'); 933 | Params := '--state "{#ServiceName}"'; 934 | // ServMan --state exit code 904 = running 935 | result := ExecEx(FileName, Params, true) = 904; 936 | end; 937 | 938 | function StopService(): Boolean; 939 | var 940 | FileName, Params: string; 941 | Status: Integer; 942 | begin 943 | FileName := ExpandConstant('{app}\ServMan.exe'); 944 | Params := '--stop "{#ServiceName}"'; 945 | Status := ExecEx(FileName, Params, true); 946 | result := (Status = 0) or (Status = ERROR_SERVICE_NOT_ACTIVE); 947 | end; 948 | 949 | function StartService(): Boolean; 950 | var 951 | FileName, Params: string; 952 | Status: Integer; 953 | begin 954 | FileName := ExpandConstant('{app}\ServMan.exe'); 955 | Params := '--start "{#ServiceName}"'; 956 | Status := ExecEx(FileName, Params, true); 957 | result := (Status = 0) or (Status = ERROR_SERVICE_ALREADY_RUNNING); 958 | end; 959 | 960 | function FirewallRuleExists(): Boolean; 961 | begin 962 | result := ExecEx(ExpandConstant('{sys}\cscript.exe'), 963 | ExpandConstant('"{app}\{#ScriptNameSyncthingFirewallRule}" /test'), 964 | true) = 0; 965 | end; 966 | 967 | function LogonTaskExists(): Boolean; 968 | begin 969 | result := ExecEx(ExpandConstant('{sys}\cscript.exe'), 970 | ExpandConstant('"{app}\{#ScriptNameSyncthingLogonTask}" /test'), 971 | true) = 0; 972 | end; 973 | 974 | function InstallOrResetService(): Integer; 975 | var 976 | FileName, Params: string; 977 | begin 978 | FileName := ExpandConstant('{app}\asmt.exe'); 979 | Params := ExpandConstant('--init' 980 | + ' --account="' + ServiceAccountUserName + '"' 981 | + ' --accountdescription="{cm:ServiceAccountDescription}"' 982 | + ' --name="{#ServiceName}"' 983 | + ' --displayname="{cm:ServiceDisplayName}"' 984 | + ' --description="{cm:ServiceDescription}"' 985 | + ' --commandline="""{app}\shawl.exe"" run --cwd ""{app}"" --no-log --priority below-normal --restart-if 3,4 --stop-timeout {#ServiceShutdownTimeout} --' 986 | + ' ""{app}\syncthing.exe"" --home ""{autoappdata}\{#AppName}"" --no-browser --no-restart"' 987 | + ' --starttype='); 988 | if WizardIsTaskSelected('startatboot') then 989 | Params := Params + 'DelayedAuto' 990 | else 991 | Params := Params + 'Demand'; 992 | result := ExecEx(FileName, Params, true); 993 | end; 994 | 995 | function SetAppDataDirectoryPermissions(): Integer; 996 | var 997 | TargetPath, FileName, Params: string; 998 | begin 999 | // icacls to reset permissions 1000 | TargetPath := ExpandConstant('{autoappdata}\{#AppName}'); 1001 | FileName := ExpandConstant('{sys}\icacls.exe'); 1002 | Params := '"' + TargetPath + '" /reset /t'; 1003 | ExecEx(FileName, Params, true); 1004 | // Grant only SYSTEM, Administrators, and service account 1005 | Params := '"' + TargetPath + '" /inheritance:r' 1006 | + ' /grant "*S-1-5-18:(OI)(CI)F"' // S-1-5-18 = SYSTEM 1007 | + ' /grant "*S-1-5-32-544:(OI)(CI)F"' // S-1-5-32-544 = Administrators 1008 | + ' /grant "' + ServiceAccountUserName + ':(OI)(CI)M"'; 1009 | result := ExecEx(FileName, Params, true); 1010 | // attrib to set app data directory and files to "not content indexed" 1011 | // (strangely, "+i" means "not content indexed") 1012 | FileName := ExpandConstant('{sys}\attrib.exe'); 1013 | Params := '+i "' + TargetPath + '"'; 1014 | ExecEx(FileName, Params, true); 1015 | Params := '+i "' + TargetPath + '\*" /s /d'; 1016 | ExecEx(FileName, Params, true); 1017 | end; 1018 | 1019 | function SetAppDirectoryPermissions(): Integer; 1020 | var 1021 | TargetPath, FileName, Params: string; 1022 | begin 1023 | TargetPath := ExpandConstant('{app}'); 1024 | // Reset permissions 1025 | FileName := ExpandConstant('{sys}\icacls.exe'); 1026 | Params := '"' + TargetPath + '" /reset /t'; 1027 | ExecEx(FileName, Params, true); 1028 | // Grant permissions to service account 1029 | Params := '"' + TargetPath + '" /grant "' + ServiceAccountUserName + ':(OI)(CI)M"'; 1030 | result := ExecEx(FileName, Params, true); 1031 | end; 1032 | 1033 | function SetupConfiguration(): Integer; 1034 | var 1035 | FileName, Params: string; 1036 | begin 1037 | FileName := ExpandConstant('{sys}\cscript.exe'); 1038 | Params := ExpandConstant('"{app}\{#ScriptNameSetSyncthingConfig}"'); 1039 | if IsAdminInstallMode() then 1040 | Params := Params + ' /service' 1041 | else 1042 | Params := Params + ' /currentuser'; 1043 | Params := Params + ' /autoupgradeinterval:' + AutoUpgradeInterval 1044 | + ' /guiaddress:"' + ListenAddress + ':' + ListenPort + '"' 1045 | + ' /relaysenabled:' + RelaysEnabled; 1046 | if WizardSilent() then 1047 | Params := Params + ' /silent'; 1048 | result := ExecEx(FileName, Params, true); 1049 | end; 1050 | 1051 | function DisableServiceAccountAndRemoveService(): Integer; 1052 | var 1053 | FileName, Params: string; 1054 | begin 1055 | FileName := ExpandConstant('{app}\asmt.exe'); 1056 | Params := ExpandConstant('--remove' 1057 | + ' --name="{#ServiceName}"' 1058 | + ' --account="' + ServiceAccountUserName + '"'); 1059 | result := ExecEx(FileName, Params, true); 1060 | end; 1061 | 1062 | function JoinPath(Path1, Path2: string): string; 1063 | begin 1064 | // Remove trailing '\' from Path1 1065 | while Path1[Length(Path1)] = '\' do 1066 | Path1 := Copy(Path1, 1, Length(Path1) - 1); 1067 | // Remove leading '\' from Path2 1068 | while Path2[1] = '\' do 1069 | Path2 := Copy(Path2, 2, Length(Path2) - 1); 1070 | // Concatenate with '\' separator 1071 | result := Path1 + '\' + Path2; 1072 | end; 1073 | 1074 | function PrepareToInstall(var NeedsRestart: Boolean): string; 1075 | var 1076 | InstalledSetupVersion: string; 1077 | begin 1078 | result := ''; 1079 | if IsISPackageInstalled() <> InstallTypeNotInstalled then 1080 | begin 1081 | InstalledSetupVersion := GetIniString('Setup', 'Version', '', ExpandConstant('{app}\{#IniFileName}')); 1082 | if (InstalledSetupVersion = '') or 1083 | (CompareVersionStrings(InstalledSetupVersion, '{#UninstallIfSetupVersionOlderThan}') < 0) then 1084 | begin 1085 | // Uninstall if: 1086 | // Package is installed AND 1087 | // Can't get setup version from SetupVersion.ini, OR 1088 | // Version in SetupVersion.ini is older than {#UninstallIfVersionOlderThan} 1089 | Log(CustomMessage('PrepareToInstallUninstallNeeded')); 1090 | if UninstallISPackage() = 0 then 1091 | Log(CustomMessage('PrepareToInstallUninstallSucceeded')) 1092 | else 1093 | begin 1094 | result := CustomMessage('PrepareToInstallErrorMessage0'); 1095 | exit; 1096 | end 1097 | end 1098 | else if CompareVersionStrings(InstalledSetupVersion, '{#SetupVersion}') > 0 then 1099 | begin 1100 | // Installed version > installing version = downgrade 1101 | result := FmtMessage(CustomMessage('PrepareToInstallErrorMessage1'), [InstalledSetupVersion, '{#SetupVersion}']); 1102 | exit; 1103 | end; 1104 | if not IsAdminInstallMode() then 1105 | begin 1106 | if IsSyncthingRunning() then 1107 | ExecEx(ExpandConstant('{app}\stctl.exe'), '--stop -q', true); 1108 | end 1109 | else 1110 | begin 1111 | if ServiceRunning() then 1112 | StopService(); 1113 | end; 1114 | end; 1115 | end; 1116 | 1117 | procedure CurStepChanged(CurStep: TSetupStep); 1118 | var 1119 | Version, Params, FileName: string; 1120 | begin 1121 | if CurStep = ssPostInstall then 1122 | begin 1123 | ExecEx(ExpandConstant('{tmp}\unzip.exe'), 1124 | ExpandConstant(Format('-jo -d "{app}" "%s" {#UnzipPattern}', [ZipFilePath])), true); 1125 | if GetVersionNumbersString(ExpandConstant('{app}\syncthing.exe'), Version) then 1126 | begin 1127 | Log(FmtMessage(CustomMessage('InstalledVersion'), [Version])); 1128 | SetIniString('InstalledVersion', 'Version', Version, ExpandConstant('{app}\{#IniFileName}')); 1129 | end; 1130 | if IsAdminInstallMode() then 1131 | begin 1132 | InstallOrResetService(); 1133 | SetAppDirectoryPermissions(); 1134 | SetAppDataDirectoryPermissions(); 1135 | end 1136 | else 1137 | begin 1138 | if WizardIsTaskSelected('startatlogon') then 1139 | begin 1140 | Params := '/create /silent'; 1141 | if WizardIsTaskSelected('startatlogon\acpoweronly') then 1142 | Params := Params + ' /startonacpoweronly'; 1143 | end 1144 | else 1145 | begin 1146 | Params := '/remove /silent'; 1147 | end; 1148 | ExecEx(ExpandConstant('{sys}\cscript.exe'), ExpandConstant('"{app}\{#ScriptNameSyncthingLogonTask}" ') + Params, true); 1149 | end; 1150 | SetupConfiguration(); 1151 | if WizardIsTaskSelected('startafterinstall') then 1152 | begin 1153 | ExecEx(ExpandConstant('{app}\stctl.exe'), '--start -q', true); 1154 | end 1155 | else if WizardIsTaskSelected('startserviceafterinstall') then 1156 | begin 1157 | if ServiceExists() and (not ServiceRunning()) then 1158 | StartService(); 1159 | end; 1160 | if not WizardIsTaskSelected('desktopicon') then 1161 | begin 1162 | FileName := ExpandConstant('{autodesktop}\{cm:ShortcutNameConfigurationPage}.lnk'); 1163 | if FileExists(FileName) then 1164 | begin 1165 | if DeleteFile(FileName) then 1166 | Log(FmtMessage(CustomMessage('FileDeleteSucceeded'), [FileName])) 1167 | else 1168 | Log(FmtMessage(CustomMessage('FileDeleteFailed'), [FileName])); 1169 | end; 1170 | end; 1171 | end; 1172 | end; 1173 | 1174 | procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); 1175 | begin 1176 | if CurUninstallStep = usUninstall then 1177 | begin 1178 | if IsAdminInstallMode() then 1179 | begin 1180 | if ServiceRunning() then 1181 | StopService(); 1182 | DisableServiceAccountAndRemoveService(); 1183 | end 1184 | else 1185 | begin 1186 | ExecEx(ExpandConstant('{app}\stctl.exe'), '--stop -q', true); 1187 | if not UninstallSilent() then 1188 | begin 1189 | if FirewallRuleExists() then 1190 | begin 1191 | // Prompt to remove Windows Firewall rule 1192 | ExecEx(ExpandConstant('{sys}\wscript.exe'), 1193 | ExpandConstant('"{app}\{#ScriptNameSyncthingFirewallRule}" /remove'), 1194 | false); 1195 | end; 1196 | end; 1197 | end; 1198 | end; 1199 | end; 1200 | 1201 | procedure DeinitializeUninstall(); 1202 | var 1203 | AppDir: string; 1204 | begin 1205 | // Try to remove {app} at uninstall if it still exists 1206 | AppDir := ExpandConstant('{app}'); 1207 | if DirExists(AppDir) then 1208 | begin 1209 | if RemoveDir(AppDir) then 1210 | Log(FmtMessage(CustomMessage('DeinitializeUninstallAppDirRemoveSucceeded'), [AppDir])) 1211 | else 1212 | Log(FmtMessage(CustomMessage('DeinitializeUninstallAppDirRemoveFailed'), [AppDir])); 1213 | end; 1214 | end; 1215 | --------------------------------------------------------------------------------