~sotirisp/kindleto

d604468f5200056640a1da14d1cdab9e63c63b56 — Sotiris Papatheodorou a month ago 307c610
Allow setting the path to the TOFU cache
2 files changed, 36 insertions(+), 14 deletions(-)

M certificates.go
M kindleto.go
M certificates.go => certificates.go +33 -13
@@ 343,17 343,36 @@ func saveClientCert(u *url.URL, name string) {
}

// saveTOFU saves known TLS server certificates to a file.
func saveTOFU() {
	d, err := os.UserCacheDir()
	if err != nil {
		optTrust = true
		log.Println("saveTOFU: unable to find cache directory, so certificate validation is disabled:", err)
func saveTOFU(optTofuFile string) {
	var tofuFile string
	if optTofuFile != "" {
		tofuFile = optTofuFile
	} else {
		cacheDir, err := os.UserCacheDir()
		if err != nil {
			log.Println("saveTOFU: error finding cache directory, disabling certificate validation:", err)
			return
		}
		if os.MkdirAll(cacheDir, 0777) != nil {
			log.Println("saveTOFU: error creating cache directory, disabling certificate validation:", err)
			return
		}
		tofuFile = path.Join(cacheDir, "kindleto-tofu.txt")
	}

	if _, err := os.Stat(tofuFile); os.IsNotExist(err) {
		f, err := os.Create(tofuFile);
		f.Close()
		if err != nil {
			log.Printf("saveTOFU: error creating TOFU cache file '%s', disabling certificate validation: %v\n", tofuFile, err)
			return
		}
	}
	tofuFile := path.Join(d, "kindleto-tofu.txt")

	f, err := os.Open(tofuFile)
	if err != nil {
		log.Printf("saveTOFU: failed to read TOFU cache file '%s': %v", tofuFile, err)
		log.Printf("saveTOFU: error opening TOFU cache file '%s', disabling certificate validation: %v\n", tofuFile, err)
		return
	}
	scanner := bufio.NewScanner(f)
	muServerCerts.Lock()


@@ 370,11 389,12 @@ func saveTOFU() {
		}
	}
	if err := scanner.Err(); err != nil {
		log.Printf("saveTOFU: failed reading line from '%s': %v", tofuFile, err)
		log.Printf("saveTOFU: error reading TOFU cache file '%s': %v\n", tofuFile, err)
	}
	muServerCerts.Unlock()
	f.Close()

	tofuUpdateInterval := 10 * time.Second
	fails := 0
	for !optTrust {
		now := time.Now()


@@ 393,12 413,12 @@ func saveTOFU() {
			f, err := os.Create(tofuFile)
			if err != nil {
				fails++
				log.Printf("saveTOFU: failed to open TOFU cache file '%s' for writing: %v", tofuFile, err)
				time.Sleep(10 * time.Minute)
				log.Printf("saveTOFU: error writing TOFU cache file '%s': %v\n", tofuFile, err)
				if fails > 10 {
					optTrust = true
					log.Printf("saveTOFU: failed to open TOFU cache file '%s' for writing %d times, so certificate validation is disabled", tofuFile, fails)
					log.Printf("saveTOFU: error writing TOFU cache file '%s' %d times, disabling certificate validation\n", tofuFile, fails)
					return
				}
				time.Sleep(tofuUpdateInterval)
				continue
			}
			muServerCerts.RLock()


@@ 409,7 429,7 @@ func saveTOFU() {
			f.Close()
		}

		time.Sleep(10 * time.Minute)
		time.Sleep(tofuUpdateInterval)
	}
}


M kindleto.go => kindleto.go +3 -1
@@ 39,6 39,7 @@ var optPort string
var optTextOnly bool
var optTrust bool
var optWebRoot string
var optTofuFile string
var muServerCerts sync.RWMutex
var serverCerts []serverCertificate
var serverCertsChanged bool


@@ 102,6 103,7 @@ func init() {
	flag.StringVar(&optLang, "lang", "en-US", "RFC4646 language for pages that do not supply one")
	flag.StringVar(&optPort, "port", "1965", "port on which to serve web interface")
	flag.StringVar(&optWebRoot, "webroot", "", "directory containing custom web templates for the proxy")
	flag.StringVar(&optTofuFile, "tofucache", "", "file where TOFU certificates are cached")
	flag.Parse()

	if optWebRoot != "" {


@@ 192,7 194,7 @@ func init() {

func main() {
	if !optTrust {
		go saveTOFU()
		go saveTOFU(optTofuFile)
	}

	if optHours > 0 {