Skip to content

Commit 299872f

Browse files
author
Delta-Kronecker
committed
workflow: publish GitHub Release from workflow_dispatch tag input; launcher: no auto system proxy, Ctrl+P toggle, --update-bridges subcommand
1 parent 8042c21 commit 299872f

3 files changed

Lines changed: 180 additions & 14 deletions

File tree

.github/workflows/build.yml

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ name: Build Tor for Windows
33
on:
44
push:
55
branches: [main, master]
6+
tags: ['v*']
67
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: 'Release tag (e.g. v1.0.0). Leave empty for a build-only run.'
11+
required: false
12+
default: ''
713

814
permissions:
9-
contents: read
15+
contents: write
1016

1117
jobs:
1218
transports:
@@ -145,3 +151,53 @@ jobs:
145151
with:
146152
name: build-log-win
147153
path: tor-src/build-win.log
154+
155+
release:
156+
name: Publish GitHub Release
157+
runs-on: ubuntu-latest
158+
needs: [tor-win64]
159+
if: |
160+
(github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') ||
161+
startsWith(github.ref, 'refs/tags/')
162+
steps:
163+
- name: Resolve tag
164+
id: tag
165+
shell: bash
166+
run: |
167+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
168+
TAG="${{ github.event.inputs.tag }}"
169+
else
170+
TAG="${GITHUB_REF#refs/tags/}"
171+
fi
172+
echo "TAG=$TAG" >> "$GITHUB_OUTPUT"
173+
echo "Publishing release tag: $TAG"
174+
175+
- uses: actions/download-artifact@v4
176+
with:
177+
name: tor-win64-portable
178+
path: release
179+
180+
- name: Package portable folder into zip
181+
shell: bash
182+
run: |
183+
cd release
184+
zip -r "../tor-win64-portable-${{ steps.tag.outputs.TAG }}.zip" start-tor.exe data
185+
ls -la ../
186+
187+
- name: Publish release
188+
shell: bash
189+
env:
190+
GH_TOKEN: ${{ github.token }}
191+
run: |
192+
TAG="${{ steps.tag.outputs.TAG }}"
193+
ZIP="tor-win64-portable-$TAG.zip"
194+
if gh release view "$TAG" --repo "${{ github.repository }}" >/dev/null 2>&1; then
195+
gh release upload "$TAG" "$ZIP" --repo "${{ github.repository }}" --clobber
196+
else
197+
gh release create "$TAG" "$ZIP" \
198+
--repo "${{ github.repository }}" \
199+
--title "Tor Portable for Iran $TAG" \
200+
--notes "Portable Tor for Iran (official tor 0.4.9.11).
201+
Unzip and run start-tor.exe - pick a mode (direct / webtunnel / obfs4 / vanilla).
202+
- SocksPort 127.0.0.1:9050, HTTP proxy 127.0.0.1:8118, DNS 127.0.0.1:53530"
203+
fi

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@ data\
2424
- **1 Direct** — no bridges (works when Tor is not blocked)
2525
- **2 WebTunnel**, **3 Obfs4**, **4 Vanilla** — bridges from `data\bridges\`
2626
Your choice is remembered for next time (`data\mode.txt`).
27-
3. On 100% bootstrap the system proxy is enabled (HTTP 127.0.0.1:8118,
28-
SOCKS5 127.0.0.1:9050, DNS 127.0.0.1:53530). Press Enter to stop and restore.
27+
3. On 100% bootstrap Tor is running. The system proxy is NOT changed
28+
automatically — press **Ctrl+P** (or **Ctrl+ح** on a Persian keyboard) to
29+
toggle it on/off (HTTP 127.0.0.1:8118). Press **Ctrl+C** to stop Tor.
30+
SOCKS5 is at 127.0.0.1:9050 and DNS at 127.0.0.1:53530.
2931

3032
You can also launch with a fixed mode or command:
3133

3234
```
3335
start-tor.exe obfs4 start directly in obfs4 mode
3436
start-tor.exe --newcircuit request a new identity (NEWNYM)
37+
start-tor.exe --update-bridges re-download the bridge lists from the
38+
Tor-Bridges-Collector repo and replace them
39+
in data\bridges\
3540
start-tor.exe --stop stop Tor and restore the proxy
3641
```
3742

scripts/start-tor.cs

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// start-tor.cs - builds to start-tor.exe (compile with build-start-tor.ps1)
1+
// start-tor.cs - builds to start-tor.exe (compile with build-start-tor.ps1)
22
// Portable Tor launcher for Iran. Expected layout next to this exe:
33
// start-tor.exe
44
// data\
@@ -7,13 +7,15 @@
77
// bridges\ <- obfs4_tested.txt, webtunnel_tested.txt, vanilla_tested.txt
88
// data\ <- runtime state (tor.log, cached-*, keys)
99
// The user picks a connection mode (direct / webtunnel / obfs4 / vanilla); the
10-
// program writes data\torrc and starts tor, then enables the Windows system
11-
// proxy (HTTP 127.0.0.1:8118). Press Enter to stop and restore the proxy.
12-
// Subcommands: --newcircuit, --stop, --bootstrap-only [mode].
10+
// program writes data\torrc and starts tor. Tor is NOT set as the system proxy
11+
// automatically: press Ctrl+P (Ctrl+ح on a Persian keyboard) to toggle the
12+
// Windows system proxy (HTTP 127.0.0.1:8118) on/off. Ctrl+C stops tor.
13+
// Subcommands: --newcircuit, --stop, --update-bridges, --bootstrap-only [mode].
1314
using System;
1415
using System.Collections.Generic;
1516
using System.Diagnostics;
1617
using System.IO;
18+
using System.Net;
1719
using System.Net.Sockets;
1820
using System.Reflection;
1921
using System.Runtime.InteropServices;
@@ -44,6 +46,9 @@ internal static class Program
4446

4547
private static readonly string[] ModeNames = { "direct", "webtunnel", "obfs4", "vanilla" };
4648
private static readonly string[] BridgeFiles = { "", "webtunnel_tested.txt", "obfs4_tested.txt", "vanilla_tested.txt" };
49+
private static readonly string[] AllBridgeFiles = { "obfs4_tested.txt", "webtunnel_tested.txt", "vanilla_tested.txt" };
50+
private const string BridgesBaseUrl =
51+
"https://raw.githubusercontent.com/Delta-Kronecker/Tor-Bridges-Collector/refs/heads/main/bridge";
4752

4853
private static Process torProc;
4954
private static bool cleaned;
@@ -221,6 +226,74 @@ private static bool WriteTorrc(int mode)
221226
return true;
222227
}
223228

229+
private static int CountBridgeLines(string path)
230+
{
231+
int n = 0;
232+
foreach (string line in File.ReadAllLines(path))
233+
{
234+
string t = line.Trim();
235+
if (t.Length == 0 || t.StartsWith("#")) continue;
236+
if (t.Contains("2001:db8")) continue;
237+
n++;
238+
}
239+
return n;
240+
}
241+
242+
private static int UpdateBridges()
243+
{
244+
try
245+
{
246+
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
247+
}
248+
catch { }
249+
250+
Directory.CreateDirectory(BridgesDir);
251+
Console.WriteLine("Updating bridge files from " + BridgesBaseUrl);
252+
Console.WriteLine(" -> " + BridgesDir);
253+
Console.WriteLine();
254+
255+
int ok = 0;
256+
foreach (string f in AllBridgeFiles)
257+
{
258+
string dest = Path.Combine(BridgesDir, f);
259+
string tmp = dest + ".tmp";
260+
string url = BridgesBaseUrl + "/" + f;
261+
try
262+
{
263+
using (WebClient wc = new WebClient())
264+
{
265+
wc.Headers[HttpRequestHeader.UserAgent] = "start-tor-updater/1.0";
266+
wc.DownloadFile(url, tmp);
267+
}
268+
int n = CountBridgeLines(tmp);
269+
if (n == 0)
270+
{
271+
Console.WriteLine("[!] " + f + ": downloaded file has no usable bridges - keeping old.");
272+
try { File.Delete(tmp); } catch { }
273+
continue;
274+
}
275+
File.Copy(tmp, dest, true);
276+
try { File.Delete(tmp); } catch { }
277+
Console.WriteLine("[i] " + f + ": " + n + " bridges - updated.");
278+
ok++;
279+
}
280+
catch (Exception ex)
281+
{
282+
Console.WriteLine("[x] " + f + ": " + ex.Message);
283+
}
284+
}
285+
286+
Console.WriteLine();
287+
if (ok == AllBridgeFiles.Length)
288+
{
289+
Console.WriteLine("All bridge files are up to date.");
290+
return 0;
291+
}
292+
Console.WriteLine("Updated " + ok + " of " + AllBridgeFiles.Length +
293+
" bridge files (restart tor to use the new bridges).");
294+
return ok > 0 ? 0 : 1;
295+
}
296+
224297
private static int StopTor()
225298
{
226299
Process p = FindTor();
@@ -252,6 +325,11 @@ private static int Main(string[] args)
252325
{
253326
return StopTor();
254327
}
328+
if (args.Length > 0 &&
329+
(args[0] == "--update-bridges" || args[0] == "--update" || args[0] == "-u"))
330+
{
331+
return UpdateBridges();
332+
}
255333

256334
int mode = -1;
257335
bool bootstrapOnly = false;
@@ -368,6 +446,7 @@ private static int Main(string[] args)
368446

369447
Console.WriteLine();
370448
Console.WriteLine("Bootstrapped 100% - Tor is UP.");
449+
Console.WriteLine();
371450

372451
if (bootstrapOnly)
373452
{
@@ -376,14 +455,40 @@ private static int Main(string[] args)
376455
return 0;
377456
}
378457

379-
SetSystemProxy(true);
380-
Console.WriteLine("System proxy set to 127.0.0.1:8118");
381-
Console.WriteLine(" SOCKS5 127.0.0.1:9050");
382-
Console.WriteLine(" HTTP 127.0.0.1:8118");
383-
Console.WriteLine(" DNS 127.0.0.1:53530");
458+
bool proxyOn = false;
459+
Console.WriteLine(" Ctrl+P (Ctrl+ح) toggle the Windows system proxy on/off");
460+
Console.WriteLine(" Ctrl+C stop Tor and exit");
461+
Console.WriteLine(" Proxy OFF");
384462
Console.WriteLine();
385-
Console.WriteLine("Press Enter to stop Tor and restore the system proxy...");
386-
try { Console.ReadLine(); } catch { }
463+
while (true)
464+
{
465+
bool alive = true;
466+
if (torProc != null)
467+
{
468+
try { torProc.Refresh(); alive = !torProc.HasExited; }
469+
catch { alive = false; }
470+
}
471+
if (!alive)
472+
{
473+
Console.WriteLine("[x] tor exited with code " + (torProc != null ? torProc.ExitCode : -1) + ".");
474+
break;
475+
}
476+
try
477+
{
478+
if (Console.KeyAvailable)
479+
{
480+
ConsoleKeyInfo ki = Console.ReadKey(true);
481+
if ((ki.Modifiers & ConsoleModifiers.Control) != 0 && ki.Key == ConsoleKey.P)
482+
{
483+
proxyOn = !proxyOn;
484+
SetSystemProxy(proxyOn);
485+
Console.WriteLine(" [i] System proxy " + (proxyOn ? "ON (127.0.0.1:8118)" : "OFF"));
486+
}
487+
}
488+
}
489+
catch { }
490+
Thread.Sleep(150);
491+
}
387492

388493
Cleanup();
389494
Console.WriteLine("Tor stopped; system proxy restored.");

0 commit comments

Comments
 (0)