Skip to content
This repository has been archived by the owner on Aug 6, 2023. It is now read-only.

Use salt when generating ids from ips #8

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions add-comment/add_comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ func getId(ip string) string {
ip = strings.ReplaceAll(ip, "_", ":") // Use real IP address, not sanitized
h := sha256.New()
h.Write([]byte(ip))
shared.WriteIPSalt(h)
// First 8 chars
return fmt.Sprintf("%x", h.Sum(nil))[:8]
}
Expand Down
12 changes: 12 additions & 0 deletions example-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ data = "/home/username/.local/share/gemlikes"
# It must be accessible to the user that the CGI script runs under.
# Directories will be created as needed, don't create them yourself.

# Where to store IP salt:
ip_salt = "auto" # default
#ip_salt = "disabled" # disable IP salting (old behavior)
#ip_salt = "/usr/local/etc/gemlikes/ip_salt" # use existing salt
# If unset, the default is "auto", which places the salt in the data directory,
# generating it the first time if needed. "disabled" restores the old behavior,
# which can potentially expose IP addresses to sufficiently-motivated attackers.
# Specifying an absolute path uses the contents of the given file as a salt,
# which must already exist. This allows multiple instances of gemlikes (e.g. in
# a shared environment) to present identical identifiers for the same IP. The
# path should be somewhere the server won't serve.

# The list of directories where files exist that can be liked and commented on:
dirs = ["/var/gemini", "/var/gemini/my_gemlog"]
# IMPORTANT: There can't be any files with same name in any of these directories,
Expand Down
40 changes: 40 additions & 0 deletions shared/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
package shared

import (
"crypto/rand"
"errors"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
"path/filepath"
Expand All @@ -15,6 +18,8 @@ import (
var ErrConfigDir = errors.New("config dir invalid or not set")
var LikesDisabled = false

var ipSaltValue []byte

func PathExists(path string) bool {
_, err := os.Stat(path)
if err == nil {
Expand Down Expand Up @@ -93,6 +98,12 @@ func SafeInit() error {
if config.Get("disable_likes") != nil {
LikesDisabled = config.Get("disable_likes").(bool)
}
// Load IP->ID salt
ipSaltValue, err = loadIPSalt(config, data.(string))
if err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -176,6 +187,35 @@ func GetTmpDir() string {
return filepath.Join(getDataDir(), "tmp")
}

func WriteIPSalt(w io.Writer) (int, error) {
return w.Write(ipSaltValue)
}

func loadIPSalt(config *toml.Tree, dataDir string) ([]byte, error) {
ipSaltMethod := "auto"
if key := config.Get("ip_salt"); key != nil {
ipSaltMethod = key.(string)
}

ipSaltPath := ipSaltMethod
switch ipSaltMethod {
case "disabled":
return nil, nil
case "auto":
ipSaltPath = filepath.Join(dataDir, "ip_salt")
f, err := os.OpenFile(ipSaltPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o644)
if err == nil {
// First time, create random data
defer f.Close()
if _, err := io.CopyN(f, rand.Reader, 16); err != nil {
return nil, err
}
}
}

return ioutil.ReadFile(ipSaltPath)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we just created the salt, then this line will try to read from that file before it's even closed. It would be better to just return the salt after creating it on line 210, if there's no error.

}

func getConfigDir() string {
e, _ := os.Executable()
return filepath.Dir(e)
Expand Down