Set up a system tray application. Download Tor Browser over I2P. This accomplishes all basic features.

This commit is contained in:
idk
2022-02-15 00:24:30 -05:00
parent 060d885666
commit 3352191180
7 changed files with 61 additions and 21 deletions

View File

@ -43,7 +43,7 @@ The plugin will not start a Tor instance if a SOCKS proxy is open on port 9050.
![Screenshot](screenshot-i2pbrowser.png) ![Screenshot](screenshot-i2pbrowser.png)
### Primary Goals ### Primary Goals(Done):
1. Ship known-good public keys, download a current Tor for the platform in the background, authenticate it, and launch it only if necessary. 1. Ship known-good public keys, download a current Tor for the platform in the background, authenticate it, and launch it only if necessary.
- Works on Windows, Linux, OSX - Works on Windows, Linux, OSX
@ -54,16 +54,16 @@ The plugin will not start a Tor instance if a SOCKS proxy is open on port 9050.
4. Work as an I2P Plugin OR as a freestanding app to be compatible with all I2P distributions 4. Work as an I2P Plugin OR as a freestanding app to be compatible with all I2P distributions
- Works on Linux, Windows, OSX - Works on Linux, Windows, OSX
5. Download Tor Browser from an in-I2P mirror(or one of a network of in-I2P mirrors) 5. Download Tor Browser from an in-I2P mirror(or one of a network of in-I2P mirrors)
- Not done - Works on Linux, Windows, OSX
### Secondary Goals: ### Secondary Goals(Also done):
1. Launch Tor Browser 1. Launch Tor Browser
- Works on Linux, Windows, OSX - Works on Linux, Windows, OSX
2. Configure and launch Tor browser for use with I2P 2. Configure and launch Tor browser for use with I2P
- Works on Linux, Windows, OSX - Works on Linux, Windows, OSX
#### Optional Features I might add if there is interest #### Optional Features I might add if there is interest(Not much stopping me...):
1. Mirror the files which it downloads to an I2P Site 1. Mirror the files which it downloads to an I2P Site
- Works on Windows, Linux, OSX - Works on Windows, Linux, OSX

View File

@ -24,10 +24,12 @@ import (
"github.com/itchio/damage" "github.com/itchio/damage"
"github.com/itchio/damage/hdiutil" "github.com/itchio/damage/hdiutil"
"github.com/itchio/headway/state" "github.com/itchio/headway/state"
"github.com/magisterquis/connectproxy"
"github.com/ulikunitz/xz" "github.com/ulikunitz/xz"
"github.com/jchavannes/go-pgp/pgp" "github.com/jchavannes/go-pgp/pgp"
"golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp"
"golang.org/x/net/proxy"
) )
// WORKING_DIR is the working directory for the application. // WORKING_DIR is the working directory for the application.
@ -74,6 +76,7 @@ type TBDownloader struct {
DownloadPath string DownloadPath string
Lang string Lang string
OS, ARCH string OS, ARCH string
Mirror string
Verbose bool Verbose bool
Profile *embed.FS Profile *embed.FS
} }
@ -252,13 +255,17 @@ func (t *TBDownloader) GetUpdaterForLangFromJSONBytes(jsonBytes []byte, ietf str
if updater, ok := platform.(map[string]interface{})[rtp]; ok { if updater, ok := platform.(map[string]interface{})[rtp]; ok {
if langUpdater, ok := updater.(map[string]interface{})[ietf]; ok { if langUpdater, ok := updater.(map[string]interface{})[ietf]; ok {
t.Log("GetUpdaterForLangFromJSONBytes()", "Found updater for language") t.Log("GetUpdaterForLangFromJSONBytes()", "Found updater for language")
return langUpdater.(map[string]interface{})["binary"].(string), langUpdater.(map[string]interface{})["sig"].(string), nil bin := langUpdater.(map[string]interface{})["binary"].(string)
sig := langUpdater.(map[string]interface{})["sig"].(string)
return t.MirrorIze(bin), t.MirrorIze(sig), nil
} }
// If we didn't find the language, try splitting at the hyphen // If we didn't find the language, try splitting at the hyphen
lang := strings.Split(ietf, "-")[0] lang := strings.Split(ietf, "-")[0]
if langUpdater, ok := updater.(map[string]interface{})[lang]; ok { if langUpdater, ok := updater.(map[string]interface{})[lang]; ok {
t.Log("GetUpdaterForLangFromJSONBytes()", "Found updater for backup language") t.Log("GetUpdaterForLangFromJSONBytes()", "Found updater for backup language")
return langUpdater.(map[string]interface{})["binary"].(string), langUpdater.(map[string]interface{})["sig"].(string), nil bin := langUpdater.(map[string]interface{})["binary"].(string)
sig := langUpdater.(map[string]interface{})["sig"].(string)
return t.MirrorIze(bin), t.MirrorIze(sig), nil
} }
// If we didn't find the language after splitting at the hyphen, try the default // If we didn't find the language after splitting at the hyphen, try the default
t.Log("GetUpdaterForLangFromJSONBytes()", "Last attempt, trying default language") t.Log("GetUpdaterForLangFromJSONBytes()", "Last attempt, trying default language")
@ -269,18 +276,42 @@ func (t *TBDownloader) GetUpdaterForLangFromJSONBytes(jsonBytes []byte, ietf str
return "", "", fmt.Errorf("t.GetUpdaterForLangFromJSONBytes: %s", ietf) return "", "", fmt.Errorf("t.GetUpdaterForLangFromJSONBytes: %s", ietf)
} }
func (t *TBDownloader) MirrorIze(replaceStr string) string {
if t.Mirror != "" {
return strings.Replace(replaceStr, "https://dist.torproject.org/torbrowser/", t.Mirror, 1)
}
return replaceStr
}
// SingleFileDownload downloads a single file from the given URL to the given path. // SingleFileDownload downloads a single file from the given URL to the given path.
// it returns the path to the downloaded file, or an error if one is encountered. // it returns the path to the downloaded file, or an error if one is encountered.
func (t *TBDownloader) SingleFileDownload(url, name string) (string, error) { func (t *TBDownloader) SingleFileDownload(dl, name string) (string, error) {
t.MakeTBDirectory() t.MakeTBDirectory()
path := filepath.Join(t.DownloadPath, name) path := filepath.Join(t.DownloadPath, name)
t.Log("SingleFileDownload()", fmt.Sprintf("Checking for updates %s to %s", url, path)) t.Log("SingleFileDownload()", fmt.Sprintf("Checking for updates %s to %s", dl, path))
if !t.BotherToDownload(url, name) { if !t.BotherToDownload(dl, name) {
t.Log("SingleFileDownload()", "File already exists, skipping download") t.Log("SingleFileDownload()", "File already exists, skipping download")
return path, nil return path, nil
} }
var d proxy.Dialer
if t.MirrorIsI2P() {
log.Println("Using I2P mirror, setting up proxy")
var err error
proxyURL, err := url.Parse("http://127.0.0.1:4444")
if err != nil {
panic(err)
}
d, err = connectproxy.New(proxyURL, proxy.Direct)
if nil != err {
panic(err)
}
}
tr := &http.Transport{
Dial: d.Dial,
}
http.DefaultClient.Transport = tr
t.Log("SingleFileDownload()", "Downloading file") t.Log("SingleFileDownload()", "Downloading file")
file, err := http.Get(url) file, err := http.Get(dl)
if err != nil { if err != nil {
return "", fmt.Errorf("SingleFileDownload: %s", err) return "", fmt.Errorf("SingleFileDownload: %s", err)
} }
@ -303,17 +334,17 @@ func FileExists(path string) bool {
// BotherToDownload returns true if we need to download a file because we don't have an up-to-date // BotherToDownload returns true if we need to download a file because we don't have an up-to-date
// version yet. // version yet.
func (t *TBDownloader) BotherToDownload(url, name string) bool { func (t *TBDownloader) BotherToDownload(dl, name string) bool {
path := filepath.Join(t.DownloadPath, name) path := filepath.Join(t.DownloadPath, name)
if !FileExists(path) { if !FileExists(path) {
return true return true
} }
defer ioutil.WriteFile(filepath.Join(t.DownloadPath, name+".last-url"), []byte(url), 0644) defer ioutil.WriteFile(filepath.Join(t.DownloadPath, name+".last-url"), []byte(dl), 0644)
lastURL, err := ioutil.ReadFile(filepath.Join(t.DownloadPath, name+".last-url")) lastURL, err := ioutil.ReadFile(filepath.Join(t.DownloadPath, name+".last-url"))
if err != nil { if err != nil {
return true return true
} }
if string(lastURL) == url { if string(lastURL) == dl {
return false return false
} }
return true return true
@ -566,3 +597,8 @@ func hTTPProxy(host, port string) bool {
} }
return false return false
} }
func (t *TBDownloader) MirrorIsI2P() bool {
// check if hostname is an I2P hostname
return strings.Contains(t.Mirror, ".i2p")
}

1
go.mod
View File

@ -25,6 +25,7 @@ require (
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 // indirect
github.com/go-stack/stack v1.8.0 // indirect github.com/go-stack/stack v1.8.0 // indirect
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 // indirect github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 // indirect
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect
github.com/mwitkow/go-http-dialer v0.0.0-20161116154839-378f744fb2b8 // indirect github.com/mwitkow/go-http-dialer v0.0.0-20161116154839-378f744fb2b8 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 // indirect github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 // indirect

2
go.sum
View File

@ -273,6 +273,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
github.com/majestrate/i2p-tools v0.0.0-20170507194519-afc8e46afa95/go.mod h1:e/TZ1O6X9t0qitnKc3xvHq8VXDpm/FmYuFf21epEkUc= github.com/majestrate/i2p-tools v0.0.0-20170507194519-afc8e46afa95/go.mod h1:e/TZ1O6X9t0qitnKc3xvHq8VXDpm/FmYuFf21epEkUc=
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=

View File

@ -29,7 +29,7 @@
<figure> <figure>
<img src="screenshot-i2pbrowser.png" alt="" /><figcaption>Screenshot</figcaption> <img src="screenshot-i2pbrowser.png" alt="" /><figcaption>Screenshot</figcaption>
</figure> </figure>
<h3 id="primary-goals">Primary Goals</h3> <h3 id="primary-goalsdone">Primary Goals(Done):</h3>
<ol type="1"> <ol type="1">
<li>Ship known-good public keys, download a current Tor for the platform in the background, authenticate it, and launch it only if necessary.</li> <li>Ship known-good public keys, download a current Tor for the platform in the background, authenticate it, and launch it only if necessary.</li>
</ol> </ol>
@ -58,9 +58,9 @@
<li>Download Tor Browser from an in-I2P mirror(or one of a network of in-I2P mirrors)</li> <li>Download Tor Browser from an in-I2P mirror(or one of a network of in-I2P mirrors)</li>
</ol> </ol>
<ul> <ul>
<li>Not done</li> <li>Works on Linux, Windows, OSX</li>
</ul> </ul>
<h3 id="secondary-goals">Secondary Goals:</h3> <h3 id="secondary-goalsalso-done">Secondary Goals(Also done):</h3>
<ol type="1"> <ol type="1">
<li>Launch Tor Browser</li> <li>Launch Tor Browser</li>
</ol> </ol>
@ -73,7 +73,7 @@
<ul> <ul>
<li>Works on Linux, Windows, OSX</li> <li>Works on Linux, Windows, OSX</li>
</ul> </ul>
<h4 id="optional-features-i-might-add-if-there-is-interest">Optional Features I might add if there is interest</h4> <h4 id="optional-features-i-might-add-if-there-is-interestnot-much-stopping-me">Optional Features I might add if there is interest(Not much stopping me…):</h4>
<ol type="1"> <ol type="1">
<li>Mirror the files which it downloads to an I2P Site</li> <li>Mirror the files which it downloads to an I2P Site</li>
</ol> </ol>

View File

@ -80,10 +80,11 @@ var (
clearnet = flag.Bool("clearnet", false, "Use clearnet (no Tor or I2P)") clearnet = flag.Bool("clearnet", false, "Use clearnet (no Tor or I2P)")
profile = flag.String("profile", "", "use a custom profile path, normally blank") profile = flag.String("profile", "", "use a custom profile path, normally blank")
help = flag.Bool("help", false, "Print help") help = flag.Bool("help", false, "Print help")
mirror = flag.String("mirror", "http://dist.torproject.i2p/torbrowser/", "Mirror to use")
/*onion = flag.Bool("onion", false, "Serve an onion site which shows some I2P propaganda, magnet links, your I2P mirror URL if configured")*/ /*onion = flag.Bool("onion", false, "Serve an onion site which shows some I2P propaganda, magnet links, your I2P mirror URL if configured")*/
/*torrent = flag.Bool("torrent", false, "Create a torrent of the downloaded files and seed it over I2P using an Open Tracker")*/ /*torrent = flag.Bool("torrent", false, "Create a torrent of the downloaded files and seed it over I2P using an Open Tracker")*/
/*ptop = flag.Bool("p2p", false, "Use bittorrent over I2P to download the initial copy of Tor Browser")*/ /*ptop = flag.Bool("p2p", false, "Use bittorrent over I2P to download the initial copy of Tor Browser")*/
/*mirror = flag.String("mirror", "", "Mirror to use")*/
) )
var client *tbserve.Client var client *tbserve.Client
@ -115,7 +116,6 @@ func main() {
} else if filename == "firefox" || *clearnet || *offline { } else if filename == "firefox" || *clearnet || *offline {
*clearnet = true *clearnet = true
} }
if *profile == "" { if *profile == "" {
if *offline { if *offline {
*profile = filepath.Join(tbget.WORKING_DIR, "profile.firefox.offline") *profile = filepath.Join(tbget.WORKING_DIR, "profile.firefox.offline")
@ -139,7 +139,7 @@ func main() {
log.Println("Using auto-detected language", *lang) log.Println("Using auto-detected language", *lang)
} }
var err error var err error
client, err = tbserve.NewClient(*verbose, *lang, *system, *arch, &content) client, err = tbserve.NewClient(*verbose, *lang, *system, *arch, *mirror, &content)
if err != nil { if err != nil {
log.Fatal("Couldn't create client", err) log.Fatal("Couldn't create client", err)
} }

View File

@ -28,10 +28,11 @@ type Client struct {
} }
// NewClient creates a new Client. // NewClient creates a new Client.
func NewClient(verbose bool, lang string, os string, arch string, content *embed.FS) (*Client, error) { func NewClient(verbose bool, lang, os, arch, mirror string, content *embed.FS) (*Client, error) {
m := &Client{ m := &Client{
TBD: tbget.NewTBDownloader(lang, os, arch, content), TBD: tbget.NewTBDownloader(lang, os, arch, content),
} }
m.TBD.Mirror = mirror
m.TBD.Verbose = verbose m.TBD.Verbose = verbose
m.TBD.MakeTBDirectory() m.TBD.MakeTBDirectory()
tgz, sig, err := m.TBD.DownloadUpdaterForLang(lang) tgz, sig, err := m.TBD.DownloadUpdaterForLang(lang)