diff --git a/get/get.go b/get/get.go index 6677bb9..2d3620d 100644 --- a/get/get.go +++ b/get/get.go @@ -150,7 +150,7 @@ func (t *TBDownloader) GetRuntimePair() string { case "386": t.ARCH = "32" default: - t.ARCH = "unknown" + t.ARCH = "64" } if t.OS != "osx" { return fmt.Sprintf("%s%s", t.OS, t.ARCH) @@ -201,8 +201,13 @@ func (t *TBDownloader) Log(function, message string) { func (t *TBDownloader) MakeTBDirectory() { os.MkdirAll(t.DownloadPath, 0755) - empath := path.Join("tor-browser", "TPO-signing-key.pub") - opath := filepath.Join(t.DownloadPath, "TPO-signing-key.pub") + tpk := "TPO-signing-key.pub" + if t.OS == "linux" && runtime.GOARCH == "arm64" { + tpk = "NOT-TPO-signing-key.pub" + } + + empath := path.Join("tor-browser", tpk) + opath := filepath.Join(t.DownloadPath, tpk) if !FileExists(opath) { t.Log("MakeTBDirectory()", "Initial TPO signing key not found, using the one embedded in the executable") bytes, err := t.Profile.ReadFile(empath) @@ -278,6 +283,16 @@ func (t *TBDownloader) GetUpdaterForLangFromJSONBytes(jsonBytes []byte, ietf str } func (t *TBDownloader) MirrorIze(replaceStr string) string { + if t.OS == "linux" && runtime.GOARCH == "arm64" { + replaceStr = strings.Replace(replaceStr, "linux64", "linux-arm64", -1) + if strings.HasSuffix(replaceStr, ".tar.xz.asc") { + //sha256sums-unsigned-build.txt.asc + lastElement := filepath.Base( + strings.Replace(replaceStr, "https://", strings.Replace(replaceStr, "http://", "", 1), 1), + ) + replaceStr = strings.Replace(replaceStr, lastElement, "sha256sums-unsigned-build.txt.asc", -1) + } + } if t.Mirror != "" { return strings.Replace(replaceStr, "https://dist.torproject.org/torbrowser/", t.Mirror, 1) } @@ -326,6 +341,26 @@ func (t *TBDownloader) SingleFileDownload(dl, name string) (string, error) { Dial: d.Dial, } http.DefaultClient.Transport = tr + } else { + log.Println("Not using I2P mirror, checking if system Tor can be used to download") + if !strings.Contains(t.Mirror, "127.0.0.1") { + if tmp, torerr := net.Listen("tcp", "127.0.0.1:9050"); torerr != nil { + proxyURL, err := url.Parse("http://127.0.0.1:9050") + 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 + } else { + tmp.Close() + } + } } t.Log("SingleFileDownload()", "Downloading file") file, err := http.Get(dl) @@ -392,28 +427,35 @@ func (t *TBDownloader) NamePerPlatform(ietf string) string { // DownloadUpdater downloads the updater for the t.Lang. It returns // the path to the downloaded updater and the downloaded detatched signature, // or an error if one is encountered. -func (t *TBDownloader) DownloadUpdater() (string, string, error) { +func (t *TBDownloader) DownloadUpdater() (string, string, string, error) { return t.DownloadUpdaterForLang(t.Lang) } // DownloadUpdaterForLang downloads the updater for the given language, overriding // t.Lang. It returns the path to the downloaded updater and the downloaded // detatched signature, or an error if one is encountered. -func (t *TBDownloader) DownloadUpdaterForLang(ietf string) (string, string, error) { +func (t *TBDownloader) DownloadUpdaterForLang(ietf string) (string, string, string, error) { binary, sig, err := t.GetUpdaterForLang(ietf) if err != nil { - return "", "", fmt.Errorf("DownloadUpdaterForLang: %s", err) + return "", "", "", fmt.Errorf("DownloadUpdaterForLang: %s", err) } sigpath, err := t.SingleFileDownload(sig, t.NamePerPlatform(ietf)+".asc") if err != nil { - return "", "", fmt.Errorf("DownloadUpdaterForLang: %s", err) + return "", "", "", fmt.Errorf("DownloadUpdaterForLang: %s", err) } binpath, err := t.SingleFileDownload(binary, t.NamePerPlatform(ietf)) if err != nil { - return "", sigpath, fmt.Errorf("DownloadUpdaterForLang: %s", err) + return "", sigpath, "", fmt.Errorf("DownloadUpdaterForLang: %s", err) } - return binpath, sigpath, nil + var sumpath string + if t.OS == "linux" && runtime.GOARCH == "arm64" { + sumpath, err = t.SingleFileDownload("https://sourceforge.net/projects/tor-browser-ports/files/11.0.6/sha256sums-unsigned-build.txt/download", t.NamePerPlatform(ietf)+".sha256sums") + if err != nil { + return "", sigpath, sumpath, fmt.Errorf("DownloadUpdaterForLang: %s", err) + } + } + return binpath, sigpath, sumpath, nil } // BrowserDir returns the path to the directory where the browser is installed. @@ -517,6 +559,9 @@ func (t *TBDownloader) UnpackUpdater(binpath string) (string, error) { // runs the updater and returns an error if one is encountered. func (t *TBDownloader) CheckSignature(binpath, sigpath string) (string, error) { pk := filepath.Join(t.DownloadPath, "TPO-signing-key.pub") + if t.OS == "linux" && runtime.GOARCH == "arm64" { + pk = filepath.Join(t.DownloadPath, "NOT-TPO-signing-key.pub") + } var err error if err = Verify(pk, sigpath, binpath); err == nil { t.Log("CheckSignature: signature", "verified successfully") diff --git a/main.go b/main.go index 1cbb577..e58e66b 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ TODO: A "Default" config file which uses hardened Tor Browser for clearnet //go:embed tor-browser/unpack/i2p.firefox.config/* //go:embed tor-browser/unpack/awo@eyedeekay.github.io.xpi //go:embed tor-browser/TPO-signing-key.pub +//go:embed tor-browser/NOT-TPO-signing-key.pub //go:embed garliconion.png //go:embed onion.png //go:embed torbrowser.desktop @@ -91,7 +92,7 @@ var ( if one is unavailable, we download over I2P instead. This is pretty fast these days really, but for 77 or so MB it's noticably delayed still. In "clearnet" modes, it might make sense to default to this mirror instead of the I2P one, or maybe offer a convenience option for just the download.*/ - mirror = flag.String("mirror", "https://dist.torproject.org/torbrowser/", "Mirror to use") + mirror = flag.String("mirror", Mirror(), "Mirror to use") solidarity = flag.Bool("onion", false, "Serve an onion site which shows some I2P propaganda") torrent = flag.Bool("torrent", tbget.TorrentReady(), "Create a torrent of the downloaded files and seed it over I2P using an Open Tracker") destruct = flag.Bool("destruct", false, "Destructively delete the working directory when finished") @@ -100,6 +101,16 @@ var ( /*ptop = flag.Bool("p2p", false, "Use bittorrent over I2P to download the initial copy of Tor Browser")*/ ) +func Mirror() string { + if tbget.TorrentReady() { + return "http://127.0.0.1:7657/i2psnark/" + } + if runtime.GOOS == "linux" && runtime.GOARCH == "arm64" { + return "https://sourceforge.net/projects/tor-browser-ports/files" + } + return "https://dist.torproject.org/torbrowser/" +} + var snowflake *bool var client *tbserve.Client diff --git a/serve/serve.go b/serve/serve.go index 9f01a18..1d39823 100644 --- a/serve/serve.go +++ b/serve/serve.go @@ -2,14 +2,19 @@ package tbserve import ( "context" + "crypto/sha256" "embed" + "encoding/hex" "fmt" + "io" "io/ioutil" "log" "net/http" + "os" "path" "path/filepath" "strconv" + "strings" "github.com/justinas/nosurf" cp "github.com/otiai10/copy" @@ -31,9 +36,9 @@ type Client struct { } // NewClient creates a new Client. -func NewClient(verbose bool, lang, os, arch, mirror string, content *embed.FS) (*Client, error) { +func NewClient(verbose bool, lang, OS, arch, mirror string, content *embed.FS) (*Client, error) { m := &Client{ - TBD: tbget.NewTBDownloader(lang, os, arch, content), + TBD: tbget.NewTBDownloader(lang, OS, arch, content), } m.TBD.Mirror = mirror m.TBD.Verbose = verbose @@ -43,10 +48,51 @@ func NewClient(verbose bool, lang, os, arch, mirror string, content *embed.FS) ( if err != nil { return nil, err } - tgz, sig, err := m.TBD.DownloadUpdaterForLang(lang) + tgz, sig, sums, err := m.TBD.DownloadUpdaterForLang(lang) if err != nil { panic(err) } + sum := "" + if sums != "" { + b, err := ioutil.ReadFile(sums) + if err != nil { + log.Fatal(err) + } + // find the line containing the checksum of our tgz file + for _, line := range strings.Split(string(b), "\n") { + if strings.Contains(line, lang+".tar.xz") { + sum = strings.Split(line, " ")[0] + break + } + } + log.Println("Checksum for ARM:" + sum) + // compute the sha256sum of the downloaded tar.xz file + f, err := os.Open(tgz) + if err != nil { + log.Fatal(err) + } + h := sha256.New() + if _, err := io.Copy(h, f); err != nil { + log.Fatal(err) + } + f.Close() + if sum != hex.EncodeToString(h.Sum(nil)) { + log.Fatal("Checksum mismatch") + } + var home string + if home, err = m.TBD.CheckSignature(sums, sig); err != nil { + log.Fatal(err) + } else { + _, err = m.TBD.UnpackUpdater(tgz) + if err != nil { + return nil, fmt.Errorf("unpacking updater: %v", err) + } + log.Printf("Signature check passed: %s %s", tgz, sig) + } + m.TBS = TBSupervise.NewSupervisor(home, lang) + go m.TBS.RunTorWithLang() + return m, nil + } var home string if home, err = m.TBD.CheckSignature(tgz, sig); err != nil { log.Fatal(err) diff --git a/tor-browser/NOT-TPO-signing-key.pub b/tor-browser/NOT-TPO-signing-key.pub new file mode 100644 index 0000000..9a4190c --- /dev/null +++ b/tor-browser/NOT-TPO-signing-key.pub @@ -0,0 +1,21 @@ + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEYLy7zxYJKwYBBAHaRw8BAQdA5PXKfnbxV/lViTGAgW34jh2jVahatLnFgKpU +i1aZVqW0HkhlaWtraSBMaW5kaG9sbSA8aG9saW5AaWtpLmZpPoiaBBMWCgBCFiEE +JPFBo7mItsNQuTdYavFdHkX9zskFAmC8u88CGwEFCQWjmoAFCwkIBwIDIgIBBhUK +CQgLAgQWAgMBAh4HAheAAAoJEGrxXR5F/c7Jp7gBAL8vm5jf36L+SL2+MsiX6pYi +uVvEMs0Fqns5UmH+eO9CAP9sTv4e1XUSG3kcNPxDHNhb390EALIKJOafuzIUFOkt +AbgzBGC8vBMWCSsGAQQB2kcPAQEHQHkjBFnRo4dXVzwJ0PTECXGk2no5CMTXwqWc +XNmrDlfFiPUEGBYKACYWIQQk8UGjuYi2w1C5N1hq8V0eRf3OyQUCYLy8EwIbAgUJ +AeEzgACBCRBq8V0eRf3OyXYgBBkWCgAdFiEEnQ+3JDWrYv30FZVUWJDtuAD3xT0F +AmC8vBMACgkQWJDtuAD3xT1KHQEAp6gkZRQYzLLCEnFDronvnGgPRMgfnzs3eCFW +x843EJoA/RWbZQeuv2tgh7pUYJk5Kzoi6PCklnw2DWuhJST9QPYMxbUBAJeTn5+q +fMa1fGLF6rcr1yvf2cO0u5ow45Tft0+jxjMNAQDlp0YaC4vF0dJF8QyWMAwgNbms +OfPns7bfiACf4DnrB7g4BGC8vFISCisGAQQBl1UBBQEBB0BZCKDIGp38Qw2HtRXj +iZcIrNUjZRKo7QuMcdZy+/gzWgMBCAeIfgQYFgoAJhYhBCTxQaO5iLbDULk3WGrx +XR5F/c7JBQJgvLxSAhsMBQkFo5qAAAoJEGrxXR5F/c7Jw8EBAMlDEXhUjZFnuwPy +hMSepnihBjoHZnmoI4EdcD40iYoLAQD9FSwq0k5Zs9rQ8U3zyif72YUS89lXoU6N +Y7OFUzKJAw== +=kH4r +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file