├── LICENSE ├── README.md └── dl-1c.sbsl /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dmitry Klimenko 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dl-1c 2 | Скрипт для скачивания релизов с сайта releases.1c.ru 3 | 4 | --- 5 | ## Использование 6 | 7 | ``` 8 | executor.cmd -s dl-1c.sbsl username password target version 9 | ``` 10 | 11 | - `username` - имя пользователя 12 | - `password` - пароль пользователя 13 | - `target` - цель для скачивания (см. ниже) 14 | - `version` - версия цели для скачивания (как на сайте, см. примеры) 15 | 16 | ### Цель для скачивания (`target`) 17 | 18 | Значение | Расшифровка 19 | -|- 20 | platform-win64 | Технологическая платформа 1С:Предприятия (64-bit) для Windows 21 | platform-win32 | Технологическая платформа 1С:Предприятия для Windows 22 | platform-osx | Клиент 1С:Предприятия для OS X 23 | server-win64 | Cервер 1С:Предприятия (64-bit) для Windows 24 | server-deb64 | Cервер 1С:Предприятия (64-bit) для DEB-based Linux-систем 25 | thinclient-win64| Тонкий клиент 1С:Предприятие (64-bit) для Windows 26 | thinclient-win32| Тонкий клиент 1С:Предприятия для Windows 27 | postgres-win | Дистрибутив СУБД PostgreSQL для Windows (64-bit) одним архивом 28 | postgres-deb | Дистрибутив СУБД PostgreSQL для Linux x86 (64-bit) одним архивом (DEB) 29 | config-* | Полная конфигурация 30 | update-* | Обновление конфигурации 31 | 32 | Для целей `config-*` и `update-*` вместо `*` указывается тег конфигурации (см. URL перехода на странице с таблицей всех релизов) 33 | 34 | ### Примеры 35 | 36 | ``` 37 | executor.cmd -s dl-1c.sbsl 77777-77 pasw0rd platform-win64 8.3.17.1496 38 | executor.cmd -s dl-1c.sbsl 77777-77 pasw0rd postgres-deb 11.7-5.1C 39 | executor.cmd -s dl-1c.sbsl 77777-77 pasw0rd config-SSL31 3.1.3.179 40 | executor.cmd -s dl-1c.sbsl 77777-77 pasw0rd update-HRM30 3.1.14.61 41 | ``` 42 | -------------------------------------------------------------------------------- /dl-1c.sbsl: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // MIT License 3 | // 4 | // Copyright (c) 2020 Dmitry Klimenko 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | const URL_RELEASE ="https://releases.1c.ru" 26 | const URL_LOGIN ="https://login.1c.ru" 27 | const URL_DOWNLOAD ="%URL_RELEASE/version_file" 28 | 29 | exception ExceptionDL1C; 30 | 31 | method updateCookies(cookies: Map, host: String, setCookie: String|Undefined) 32 | 33 | if setCookie is Undefined 34 | return; 35 | 36 | val thisCookies = new Map() 37 | 38 | for cookie in setCookie.Split(";") 39 | val pair = cookie.Split("=") 40 | val key = pair[0].Trim() 41 | if key == "Path" or key == "Expires" or pair.Size() == 1 // don't worry 42 | continue; 43 | val value = pair.Size() == 1 ? "" : pair[1].Trim() 44 | thisCookies.Insert(key, value) 45 | ; 46 | 47 | var realHost = thisCookies.ContainsKey("Domain") ? thisCookies.Get("Domain") : host 48 | if not realHost.StartsWith(".") 49 | realHost = "." + realHost 50 | ; 51 | 52 | val hostCookies = cookies.ContainsKey(realHost) ? cookies.Get(realHost) : new Map() 53 | if not cookies.ContainsKey(realHost) 54 | cookies.Insert(realHost, hostCookies) 55 | ; 56 | 57 | for item in thisCookies 58 | if item.Key == "Domain" 59 | continue; 60 | hostCookies.Insert(item.Key, item.Value) 61 | ; 62 | 63 | ; 64 | 65 | method getCookie(cookies: Map, host: String): String 66 | 67 | var result = "" 68 | 69 | val realHost = "." + host 70 | 71 | for hostItem in cookies 72 | if not realHost.EndsWith(hostItem.Key) 73 | continue; 74 | 75 | for cookie in hostItem.Value 76 | result = result + "; " + cookie.Key + (cookie.Value.IsEmpty() ? "" : "=" + cookie.Value) 77 | ; 78 | ; 79 | 80 | return result.IsEmpty() ? result : result.Substring(2) 81 | ; 82 | 83 | method getHost(url: String): String 84 | 85 | var result = "" 86 | 87 | if url.StartsWith("http://") 88 | result = url.Substring("http://".Length()) 89 | else if url.StartsWith("https://") 90 | result = url.Substring("https://".Length()) 91 | else 92 | throw new ExceptionDL1C("Bad URL: %url") 93 | ; 94 | 95 | if result.Contains("/") 96 | result = result.SubstringFromBegin(result.Find("/")) 97 | ; 98 | 99 | return result 100 | ; 101 | 102 | method baseUrl(url: String): String 103 | 104 | var result = "" 105 | 106 | if url.StartsWith("http://") 107 | result = "http://" 108 | else if url.StartsWith("https://") 109 | result = "https://" 110 | else 111 | throw new ExceptionDL1C("Bad URL: %url") 112 | ; 113 | 114 | return result + getHost(url) 115 | ; 116 | 117 | method extract(text: String, startPattern: String, endPattern: String): String 118 | val start = text.Find(startPattern) 119 | val end = text.Find(endPattern, start + startPattern.Length()) 120 | return text.Substring(start + startPattern.Length(), end) 121 | ; 122 | 123 | method exploreWeb(request: HttpRequest, cookies: Map): HttpResponse 124 | 125 | val requests = [request] 126 | val responses = [request.Execute()] 127 | updateCookies(cookies, getHost(request.AbsoluteUrl), responses.Last().Headers.GetFirst("Set-Cookie")) 128 | 129 | while responses.Last().StatusCode == 302 130 | var location = responses.Last().Headers.GetFirst("Location") as String 131 | if location.StartsWith("/") 132 | location = baseUrl(requests.Last().AbsoluteUrl) + location 133 | ; 134 | requests.Add( 135 | HttpClient.GetRequest(location) 136 | .SetCookies(getCookie(cookies, getHost(location))) 137 | .SetMaxRedirect(0) // https://github.com/klimenko-1c/dl-1c/issues/1 138 | ) 139 | responses.Add( 140 | requests.Last() 141 | .Execute() 142 | ) 143 | updateCookies(cookies, getHost(location), responses.Last().Headers.GetFirst("Set-Cookie")) 144 | ; 145 | 146 | for i = 0 to responses.Bound() - 1 147 | responses[i].Close() 148 | ; 149 | 150 | return responses.Last() 151 | ; 152 | 153 | method auth(username: String, password: String): Map 154 | 155 | val cookies = new Map() 156 | use response1 = HttpClient.GetRequest(URL_RELEASE).Execute() 157 | updateCookies(cookies, getHost(URL_RELEASE), response1.Headers.GetFirst("Set-Cookie")) 158 | val src = response1.Body.ReadAsText() 159 | response1.Close() 160 | 161 | val action = extract(src, "form method=\"post\" id=\"loginForm\" action=\"", "\"") 162 | val execution = extract(src, "input type=\"hidden\" name=\"execution\" value=\"", "\"") 163 | 164 | val body = "inviteCode=" 165 | + "&" + "inviteType=" 166 | + "&" + "username=%username" 167 | + "&" + "password=%password" 168 | + "&" + "rememberMe=on" 169 | + "&" + "execution=" + execution.Replace("=", "\%3D") 170 | + "&" + "_eventId=submit" 171 | + "&" + "geolocation=" 172 | + "&" + "submit=\%D0\%92\%D0\%BE\%D0\%B9\%D1\%82\%D0\%B8" 173 | 174 | val request = HttpClient.PostRequest(URL_LOGIN + action) 175 | .SetContentType("application/x-www-form-urlencoded") 176 | .SetCookies(getCookie(cookies, getHost(URL_LOGIN))) 177 | .SetBody(body) 178 | .SetMaxRedirect(0) // https://github.com/klimenko-1c/dl-1c/issues/1 179 | 180 | exploreWeb(request, cookies).Close() 181 | 182 | if not cookies.Get("." + getHost(URL_LOGIN)).ContainsKey("TGC") 183 | throw new ExceptionDL1C("Auth failed") 184 | ; 185 | 186 | return cookies 187 | ; 188 | 189 | method download(cookies: Map, nick: String, ver: String, path_folder: String, path_version: String, path_filename: String) 190 | 191 | val url1 = URL_DOWNLOAD 192 | + "?" + "nick=" + nick 193 | + "&" + "ver=" + ver 194 | + "&" + "path=" + path_folder + "\%5C" + path_version + "\%5C" + path_filename // https://github.com/klimenko-1c/dl-1c/issues/2 195 | 196 | val request1 = HttpClient.GetRequest(url1) 197 | .SetCookies(getCookie(cookies, getHost(url1))) 198 | .SetMaxRedirect(0) // https://github.com/klimenko-1c/dl-1c/issues/1 199 | 200 | use response1 = exploreWeb(request1, cookies) 201 | 202 | val src = response1.Body.ReadAsText() 203 | response1.Close() 204 | 205 | val end = src.Find(">Скачать дистрибутив<") 206 | val start = src.FindFromEnd("\"",, end - 1) 207 | val url2 = src.Substring(start + 1, end - 1) 208 | 209 | val request2 = HttpClient.GetRequest(url2) 210 | .SetCookies(getCookie(cookies, getHost(url2))) 211 | .SetMaxRedirect(0) // https://github.com/klimenko-1c/dl-1c/issues/1 212 | 213 | use response2 = exploreWeb(request2, cookies) 214 | 215 | use write = new File(path_filename).OpenWritableStream() 216 | response2.Body.CopyTo(write) 217 | 218 | write.Close() 219 | response2.Close() 220 | ; 221 | 222 | method downloadPlatform(cookies: Map, version: String, prefix: String, extension: String) 223 | 224 | val path_folder = "Platform" 225 | val path_version = version.Replace(".", "_") 226 | val path_filename = prefix + "_" + path_version + "." + extension 227 | 228 | val nick = path_folder + version.Split(".")[0] + version.Split(".")[1] 229 | 230 | download(cookies, nick, version, path_folder, path_version, path_filename) 231 | ; 232 | 233 | method downloadPostgres(cookies: Map, version: String, postfix: String, extension: String) 234 | 235 | val prefix = "postgresql" 236 | 237 | val path_folder = "AddCompPostgre" 238 | val path_version = version.Replace(".", "_").Replace("-", "_") 239 | val path_filename = prefix + "_" + version.Replace("-", "_") + "_" + postfix + "." + extension 240 | 241 | val nick = path_folder 242 | 243 | download(cookies, nick, version, path_folder, path_version, path_filename) 244 | ; 245 | 246 | method downloadConfiguration(cookies: Map, version: String, target: String, isUpdate: Boolean) 247 | 248 | val postfix = isUpdate ? "updsetup" : "setup1c" 249 | 250 | val path_folder = target 251 | val path_version = version.Replace(".", "_") 252 | val path_filename = path_folder + "_" + path_version + "_" + postfix + ".exe" 253 | 254 | val nick = path_folder 255 | 256 | download(cookies, nick, version, path_folder, path_version, path_filename) 257 | ; 258 | 259 | method main(username: String, password: String, target: String, version: String) 260 | 261 | val cookies = auth(username, password) 262 | 263 | if target.StartsWith("config-") or target.StartsWith("update-") 264 | downloadConfiguration(cookies, version, target.Substring(7), target.StartsWith("update-")) 265 | else 266 | 267 | case target 268 | when "platform-win64" 269 | downloadPlatform(cookies, version, "windows64full", "rar") 270 | when "platform-win32" 271 | downloadPlatform(cookies, version, "windows", "rar") 272 | when "platform-osx" 273 | downloadPlatform(cookies, version, "clientosx", "dmg") 274 | when "server-win64" 275 | downloadPlatform(cookies, version, "windows64", "rar") 276 | when "server-deb64" 277 | downloadPlatform(cookies, version, "deb64", "tar.gz") 278 | when "thinclient-win64" 279 | downloadPlatform(cookies, version, "setuptc64", "tar.gz") 280 | when "thinclient-win32" 281 | downloadPlatform(cookies, version, "setuptc", "tar.gz") 282 | when "postgres-win" 283 | downloadPostgres(cookies, version, "x64", "zip") 284 | when "postgres-deb" 285 | downloadPostgres(cookies, version, "amd64_deb", "tar.bz2") 286 | else 287 | throw new ExceptionDL1C("Bad target") 288 | ; 289 | ; 290 | ; 291 | 292 | method Script(username: String, password: String, target: String, version: String): Number 293 | 294 | try 295 | main(username, password, target, version) 296 | return 0 297 | catch exception: any 298 | Console.WriteError(exception.Info()) 299 | return 1 300 | ; 301 | ; 302 | --------------------------------------------------------------------------------