mirror of https://github.com/namecoin/ncdns
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.7 KiB
Go
135 lines
3.7 KiB
Go
package tlsoverridefirefoxsync
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/hlandau/xlog"
|
|
"gopkg.in/hlandau/easyconfig.v1/cflag"
|
|
|
|
"github.com/namecoin/ncdns/namecoin"
|
|
"github.com/namecoin/ncdns/ncdumpzone"
|
|
"github.com/namecoin/ncdns/tlsoverridefirefox"
|
|
)
|
|
|
|
var (
|
|
flagGroup = cflag.NewGroup(nil, "tlsoverridefirefox")
|
|
syncEnableFlag = cflag.Bool(flagGroup, "sync", false,
|
|
"Synchronize TLSA records from the Namecoin zone to Firefox's "+
|
|
"cert_override.txt")
|
|
firefoxProfileDirFlag = cflag.String(flagGroup, "profiledir", "",
|
|
"Firefox profile directory")
|
|
)
|
|
|
|
var log, Log = xlog.New("ncdns.tlsoverridefirefoxsync")
|
|
|
|
var zoneData string
|
|
var zoneDataReady = false
|
|
var zoneDataMux sync.Mutex
|
|
|
|
// Note: the reason for the Fatal reaction to errors is that, if we stop
|
|
// syncing the override list, Firefox will continue trusting .bit certs that
|
|
// might be revoked in Namecoin. Therefore, it is important that, in such a
|
|
// situation, .bit domains must stop resolving until the issue is corrected.
|
|
// Forcing ncdns to exit is the least complex way to achieve this.
|
|
|
|
func watchZone(conn *namecoin.Client) {
|
|
for {
|
|
var result bytes.Buffer
|
|
|
|
err := ncdumpzone.Dump(conn, &result, "firefox-override")
|
|
log.Fatale(err, "Couldn't dump zone for Firefox override sync")
|
|
|
|
zoneDataMux.Lock()
|
|
zoneData = result.String()
|
|
zoneDataReady = true
|
|
zoneDataMux.Unlock()
|
|
|
|
time.Sleep(10 * time.Minute)
|
|
}
|
|
}
|
|
|
|
func watchProfile(suffix string) {
|
|
if firefoxProfileDirFlag.Value() == "" {
|
|
log.Fatal("Missing required config option tlsoverridefirefox.profiledir")
|
|
}
|
|
|
|
for {
|
|
if profileInUse() {
|
|
time.Sleep(1 * time.Second)
|
|
continue
|
|
}
|
|
|
|
// At this point we know that Firefox is not running.
|
|
|
|
zoneDataMux.Lock()
|
|
zoneDataReadyLocal := zoneDataReady
|
|
zoneDataLocal := zoneData
|
|
zoneDataMux.Unlock()
|
|
|
|
if !zoneDataReadyLocal {
|
|
time.Sleep(1 * time.Second)
|
|
continue
|
|
}
|
|
|
|
log.Debug("Syncing zone to cert_override.txt...")
|
|
|
|
prevOverrides, err := ioutil.ReadFile(
|
|
firefoxProfileDirFlag.Value() + "/cert_override.txt")
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
// cert_override.txt doesn't exist in a default
|
|
// Firefox install; it's only created once the
|
|
// first override is configured in the Firefox
|
|
// GUI. If it's not there, we can pretend we
|
|
// read an empty file.
|
|
prevOverrides = []byte(``)
|
|
} else {
|
|
log.Fatale(err,
|
|
"Couldn't read Firefox "+
|
|
"cert_override.txt")
|
|
}
|
|
}
|
|
|
|
filteredPrevOverrides, err := tlsoverridefirefox.
|
|
FilterOverrides(string(prevOverrides), suffix)
|
|
log.Fatale(err, "Couldn't filter Firefox overrides")
|
|
|
|
newOverrides := filteredPrevOverrides + zoneDataLocal + "\n"
|
|
|
|
// TODO: Does 0600 match the default behavior of Firefox?
|
|
// TODO: maybe instead write to a temp file and then move the file into place?
|
|
err = ioutil.WriteFile(firefoxProfileDirFlag.Value()+
|
|
"/cert_override.txt", []byte(newOverrides), 0600)
|
|
log.Fatale(err, "Couldn't write Firefox cert_override.txt")
|
|
|
|
log.Debug("Finished syncing zone to cert_override.txt")
|
|
|
|
time.Sleep(10 * time.Minute)
|
|
}
|
|
}
|
|
|
|
func profileInUse() bool {
|
|
// This glob pattern matches the ".sqlite-wal" and ".sqlite-shm" files
|
|
// that are only present when Firefox's databases are open.
|
|
matches, err := filepath.Glob(firefoxProfileDirFlag.Value() + "/*.sqlite-*")
|
|
log.Fatale(err, "Couldn't check if Firefox is running for override sync")
|
|
|
|
return matches != nil
|
|
}
|
|
|
|
// Start starts 2 background threads that synchronize the blockchain's TLSA
|
|
// records to a Firefox profile's cert_override.txt. It accepts a connection
|
|
// to access Namecoin Core, as well as a host suffix (usually "bit").
|
|
func Start(conn *namecoin.Client, suffix string) error {
|
|
if syncEnableFlag.Value() {
|
|
go watchZone(conn)
|
|
go watchProfile(suffix)
|
|
}
|
|
return nil
|
|
}
|