11<#
22. SYNOPSIS
3- Fetch fresh tested Tor bridges from the Tor-Bridges-Collector GitHub repo
4- and write them to data\bridges.txt for launcher.ps1 .
3+ Fetch fresh tested Tor bridges and write a complete portable torrc NEXT TO
4+ tor.exe (template + UseBridges + Bridge lines), plus data\bridges.txt.
55
66. DESCRIPTION
7- Sources (default repo Delta-Kronecker/Tor-Bridges-Collector):
7+ Bridge sources (default repo Delta-Kronecker/Tor-Bridges-Collector):
88 bridge\obfs4_tested.txt -> obfs4 bridges
99 bridge\webtunnel_tested.txt -> webtunnel bridges
1010 bridge\vanilla_tested.txt -> plain (vanilla) bridges
1111
1212 Non-routable / documentation addresses (e.g. 2001:db8::/32, RFC1918,
13- TEST-NET) are filtered out, so placeholders never end up in bridges.txt.
13+ TEST-NET) are filtered out.
14+
15+ The resulting torrc sits next to tor.exe and uses only relative paths, so
16+ the whole folder is fully portable - no %APPDATA%, no absolute paths.
1417
1518. EXAMPLE
1619 .\fetch-bridges.ps1
1720 .\fetch-bridges.ps1 -Transports obfs4,vanilla -PerTransport 12
21+ .\fetch-bridges.ps1 -BinDir C:\Users\me\Tor-Iran
1822#>
1923param (
2024 [string ]$Transports = " obfs4,webtunnel,vanilla" ,
2125 [int ]$PerTransport = 8 ,
2226 [string ]$BaseUrl = " https://raw.githubusercontent.com/Delta-Kronecker/Tor-Bridges-Collector/refs/heads/main/bridge" ,
23- [string ]$OutFile = ( Join-Path ( Split-Path $PSScriptRoot - Parent) " data\bridges.txt " )
27+ [string ]$BinDir = " "
2428)
2529
2630$ErrorActionPreference = " Stop"
2731
32+ $Root = Split-Path $PSScriptRoot - Parent
33+ if (-not $BinDir ) {
34+ $BinDir = Join-Path $Root " bin"
35+ if (-not (Test-Path (Join-Path $BinDir " tor.exe" ))) { $BinDir = $Root }
36+ }
37+ if (-not (Test-Path (Join-Path $BinDir " tor.exe" ))) {
38+ Write-Host " [x] tor.exe not found in $BinDir "
39+ Write-Host " Point -BinDir at the folder that contains tor.exe."
40+ exit 1
41+ }
42+ $DataDir = Join-Path $BinDir " data"
43+ $TorrcPath = Join-Path $BinDir " torrc"
44+ $Template = Join-Path $Root " configs\torrc.iran"
45+ if (-not (Test-Path $Template )) { $Template = $TorrcPath }
46+ $BridgesFile = Join-Path $DataDir " bridges.txt"
47+
48+ New-Item - ItemType Directory - Force - Path $DataDir | Out-Null
49+
2850function Test-RoutableIpv4 ([string ]$ip ) {
2951 $o = $ip -split " \."
3052 if ($o.Count -ne 4 ) { return $false }
@@ -55,7 +77,6 @@ function Test-RoutableIpv6([string]$ip) {
5577}
5678
5779function Test-BridgeLine ([string ]$line ) {
58- # must contain a 40-hex fingerprint token
5980 if ($line -notmatch " \s[0-9A-Fa-f]{40}(\s|$)" ) { return $false }
6081 if ($line -match " obfs4\s+([0-9.]+):\d+" ) { return (Test-RoutableIpv4 $matches [1 ]) }
6182 if ($line -match " obfs4\s+\[([0-9a-fA-F:]+)\]:\d+" ) { return (Test-RoutableIpv6 $matches [1 ]) }
@@ -65,9 +86,6 @@ function Test-BridgeLine([string]$line) {
6586 return $false
6687}
6788
68- $dir = Split-Path $OutFile - Parent
69- New-Item - ItemType Directory - Force - Path $dir | Out-Null
70-
7189$all = @ ()
7290$failed = @ ()
7391foreach ($t in ($Transports -split " ," )) {
@@ -94,7 +112,7 @@ foreach ($t in ($Transports -split ",")) {
94112 Write-Host " [ok] $t : $ ( $valid.Count ) valid, picked $ ( $picked.Count ) "
95113 $all += $picked | ForEach-Object { " Bridge $_ " }
96114 } else {
97- Write-Host " [!!] $t : 0 usable bridges (file fetched, all filtered out or unparsable)"
115+ Write-Host " [!!] $t : 0 usable bridges (all filtered out or unparsable)"
98116 $failed += $t
99117 }
100118 } catch {
@@ -104,25 +122,35 @@ foreach ($t in ($Transports -split ",")) {
104122}
105123
106124$all = @ ($all | Select-Object - Unique)
107- if ( $all .Count -eq 0 ) {
108- Write-Host " "
109- Write-Host " No bridges fetched. Check the BaseUrl / network, or add bridges manually. "
110- Write-Host " Manual fallback: "
111- Write-Host " 1. Open https://bridges.torproject.org/options in Tor Browser "
112- Write-Host " 2. Choose 'obfs4' or 'WebTunnel' and copy the bridge lines "
113- Write-Host " 3. Save them to: $OutFile "
114- Write-Host " (each line prefixed with 'Bridge ', e.g. Bridge webtunnel 1.2.3.4:443 ...) "
115- exit 1
125+
126+ # --- regenerate the portable torrc next to tor.exe ---
127+ $base = Get-Content $Template - Raw
128+ $base = @ ( $base -split " `n " | Where-Object { $_ -notmatch " ^\s*(UseBridges\b|Bridge\b|#.*[Bb]ridge) " }) -join " `n "
129+ if ( $all .Count -gt 0 ) {
130+ $section = " `n # --- bridges fetched on $ ( Get-Date - Format ' yyyy-MM-dd HH:mm ' ) --- `n " +
131+ " UseBridges 1 `n " + ( $all -join " `n " ) + " `n "
132+ } else {
133+ $section = " "
116134}
135+ [System.IO.File ]::WriteAllText($TorrcPath , $base.TrimEnd () + $section ,
136+ (New-Object System.Text.UTF8Encoding($false )))
117137
118- $content = @ (
119- " # Bridge lines fetched on $ ( Get-Date - Format ' yyyy-MM-dd HH:mm' ) from $BaseUrl "
120- " # Each line is used by launcher .ps1. Delete lines you do not want to use. "
138+ $bridgeDoc = @ (
139+ " # Bridge lines used in $TorrcPath (fetched $ ( Get-Date - Format ' yyyy-MM-dd HH:mm' ) ) "
140+ " # To refresh: re-run fetch-bridges .ps1"
121141) + $all
122-
123- [System.IO.File ]::WriteAllText($OutFile , ($content -join " `r`n " ) + " `r`n " ,
142+ [System.IO.File ]::WriteAllText($BridgesFile , ($bridgeDoc -join " `r`n " ) + " `r`n " ,
124143 (New-Object System.Text.UTF8Encoding($false )))
144+
125145Write-Host " "
126- Write-Host " Saved $ ( $all.Count ) bridges to $OutFile "
146+ if ($all.Count -gt 0 ) {
147+ Write-Host " Updated $TorrcPath with $ ( $all.Count ) bridges."
148+ } else {
149+ Write-Host " No bridges fetched - torrc left WITHOUT bridges (direct connection)."
150+ Write-Host " Manual fallback:"
151+ Write-Host " 1. Open https://bridges.torproject.org/options in Tor Browser"
152+ Write-Host " 2. Choose 'obfs4' or 'WebTunnel' and copy the bridge lines"
153+ Write-Host " 3. Paste them into: $TorrcPath (add 'Bridge ' before each)"
154+ }
127155if ($failed.Count ) { Write-Host " No bridges for: $ ( $failed -join ' , ' ) " }
128- Write-Host " Run launcher.ps1 to start Tor with these bridges ."
156+ Write-Host " Run tor.exe (or start.bat / launcher.ps1) to connect ."
0 commit comments