mirror of https://github.com/jlelse/GoBlog
Tor single hop mode option
This commit is contained in:
parent
e3eb3a5b4e
commit
5f52993a0c
|
@ -44,6 +44,7 @@ type configServer struct {
|
||||||
TailscaleHTTPS bool `mapstructure:"tailscaleHttps"`
|
TailscaleHTTPS bool `mapstructure:"tailscaleHttps"`
|
||||||
Tailscale *configTailscale `mapstructure:"tailscale"`
|
Tailscale *configTailscale `mapstructure:"tailscale"`
|
||||||
Tor bool `mapstructure:"tor"`
|
Tor bool `mapstructure:"tor"`
|
||||||
|
TorSingleHop bool `mapstructure:"torSingleHop"`
|
||||||
SecurityHeaders bool `mapstructure:"securityHeaders"`
|
SecurityHeaders bool `mapstructure:"securityHeaders"`
|
||||||
CSPDomains []string `mapstructure:"cspDomains"`
|
CSPDomains []string `mapstructure:"cspDomains"`
|
||||||
publicHostname string
|
publicHostname string
|
||||||
|
|
|
@ -40,4 +40,8 @@ There's also the possibility to configure GoBlog to use Google Cloud's Text-to-S
|
||||||
|
|
||||||
On receiving a webmention, a new comment or a contact form submission, GoBlog will create a new notification. Notifications are displayed on `/notifications` and can be deleted by the user.
|
On receiving a webmention, a new comment or a contact form submission, GoBlog will create a new notification. Notifications are displayed on `/notifications` and can be deleted by the user.
|
||||||
|
|
||||||
If configured, GoBlog will also send a notification using a Telegram Bot or [Ntfy.sh](https://ntfy.sh/). See the `example-config.yml` file for how to configure the notification providers.
|
If configured, GoBlog will also send a notification using a Telegram Bot or [Ntfy.sh](https://ntfy.sh/). See the `example-config.yml` file for how to configure the notification providers.
|
||||||
|
|
||||||
|
## Tor Hidden Services
|
||||||
|
|
||||||
|
GoBlog can be configured to provide a Tor Hidden Service. This is useful if you want to offer your visitors a way to connect to your blog from censored networks or countries. See the `example-config.yml` file for how to enable the Tor Hidden Service. If you don't need to hide your server, you can enable the Single Hop mode.
|
|
@ -2,6 +2,14 @@
|
||||||
# Until there's an official release configuration may change
|
# Until there's an official release configuration may change
|
||||||
# Keep a look at the commit history
|
# Keep a look at the commit history
|
||||||
|
|
||||||
|
# Debug
|
||||||
|
debug: true # Enable more verbose logging
|
||||||
|
|
||||||
|
# Pprof - Option to enable pprof profiling
|
||||||
|
pprof:
|
||||||
|
enabled: true # Enable pprof profiling
|
||||||
|
address: ":6060" # Address to listen on
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
database:
|
database:
|
||||||
file: data/db.sqlite # File for the SQLite database
|
file: data/db.sqlite # File for the SQLite database
|
||||||
|
@ -25,6 +33,7 @@ server:
|
||||||
- media.example.com
|
- media.example.com
|
||||||
# Tor
|
# Tor
|
||||||
tor: true # Publish onion service, requires Tor to be installed and available in path
|
tor: true # Publish onion service, requires Tor to be installed and available in path
|
||||||
|
torSingleHop: true # Enable single hop mode (non-anonymous)
|
||||||
# Tailscale (see https://tailscale.com)
|
# Tailscale (see https://tailscale.com)
|
||||||
tailscaleHttps: true # Use an Let's Encrypt certificate from Tailscale (see https://goblog.app/s/7), requires publicHttps to be disabled
|
tailscaleHttps: true # Use an Let's Encrypt certificate from Tailscale (see https://goblog.app/s/7), requires publicHttps to be disabled
|
||||||
tailscale:
|
tailscale:
|
||||||
|
|
74
tor.go
74
tor.go
|
@ -29,32 +29,16 @@ func (a *goBlog) startOnionService(h http.Handler) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Initialize private key
|
// Initialize private key
|
||||||
torKeyPath := filepath.Join(torDataPath, "onion.pk")
|
torKey, err := a.createTorPrivateKey(torDataPath)
|
||||||
var torKey crypto.PrivateKey
|
if err != nil {
|
||||||
if _, err := os.Stat(torKeyPath); os.IsNotExist(err) {
|
return err
|
||||||
_, torKey, err = ed25519.GenerateKey(nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
x509Encoded, err := x509.MarshalPKCS8PrivateKey(torKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded})
|
|
||||||
_ = os.WriteFile(torKeyPath, pemEncoded, 0600)
|
|
||||||
} else {
|
|
||||||
d, _ := os.ReadFile(torKeyPath)
|
|
||||||
block, _ := pem.Decode(d)
|
|
||||||
x509Encoded := block.Bytes
|
|
||||||
torKey, err = x509.ParsePKCS8PrivateKey(x509Encoded)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Start tor with default config (can set start conf's DebugWriter to os.Stdout for debug logs)
|
// Start tor
|
||||||
log.Println("Starting and registering onion service, please wait a couple of minutes...")
|
log.Println("Starting and registering onion service, please wait a couple of minutes...")
|
||||||
t, err := tor.Start(context.Background(), &tor.StartConf{
|
t, err := tor.Start(context.Background(), &tor.StartConf{
|
||||||
TempDataDirBase: os.TempDir(),
|
TempDataDirBase: os.TempDir(),
|
||||||
|
NoAutoSocksPort: true,
|
||||||
|
ExtraArgs: a.torExtraArgs(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -65,9 +49,10 @@ func (a *goBlog) startOnionService(h http.Handler) error {
|
||||||
defer listenCancel()
|
defer listenCancel()
|
||||||
// Create a v3 onion service to listen on any port but show as 80
|
// Create a v3 onion service to listen on any port but show as 80
|
||||||
onion, err := t.Listen(listenCtx, &tor.ListenConf{
|
onion, err := t.Listen(listenCtx, &tor.ListenConf{
|
||||||
Version3: true,
|
Version3: true,
|
||||||
Key: torKey,
|
Key: torKey,
|
||||||
RemotePorts: []int{80},
|
RemotePorts: []int{80},
|
||||||
|
NonAnonymous: a.cfg.Server.TorSingleHop,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -91,3 +76,42 @@ func (a *goBlog) startOnionService(h http.Handler) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) createTorPrivateKey(torDataPath string) (crypto.PrivateKey, error) {
|
||||||
|
torKeyPath := filepath.Join(torDataPath, "onion.pk")
|
||||||
|
var torKey crypto.PrivateKey
|
||||||
|
if _, err := os.Stat(torKeyPath); os.IsNotExist(err) {
|
||||||
|
// Tor private key not found, create it
|
||||||
|
_, torKey, err = ed25519.GenerateKey(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x509Encoded, err := x509.MarshalPKCS8PrivateKey(torKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded})
|
||||||
|
err = os.WriteFile(torKeyPath, pemEncoded, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Tor private key found, load it
|
||||||
|
d, _ := os.ReadFile(torKeyPath)
|
||||||
|
block, _ := pem.Decode(d)
|
||||||
|
x509Encoded := block.Bytes
|
||||||
|
torKey, err = x509.ParsePKCS8PrivateKey(x509Encoded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return torKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) torExtraArgs() []string {
|
||||||
|
s := []string{"--SocksPort", "0"}
|
||||||
|
if a.cfg.Server.TorSingleHop {
|
||||||
|
s = append(s, "--HiddenServiceNonAnonymousMode", "1", "--HiddenServiceSingleHopMode", "1")
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue