Skip to content

Commit

Permalink
Wordlists as new item's ID source
Browse files Browse the repository at this point in the history
As also discussed in #34, it is now possible to specify a wordlist to be
used as source of the random ID for new items.
  • Loading branch information
oxzi committed Nov 14, 2023
1 parent 7c16e90 commit a33a40e
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Types of changes:
- Created Store RPC working on Unix domain sockets to allow a `fork`+`exec`ed daemon.
- Configuration through YAML configuration file.
- Configurable index template and static files, partially by [@riotbib](https://github.com/riotbib) in [#45](https://github.com/oxzi/gosh/pull/45).
- Configurable ID length for generated items.
- ID of new items is now configurable both in length as well as in source (random, wordlist).

### Changed
- Dependency version bumps.
Expand Down
1 change: 1 addition & 0 deletions gosh.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Config struct {
IdGenerator struct {
Type string `yaml:"type"`
Length int `yaml:"length"`
File string `yaml:"file"`
} `yaml:"id_generator"`
}

Expand Down
12 changes: 9 additions & 3 deletions gosh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ store:

# id_generator specifies how the ID resp. name of new elements is generated.
id_generator:
# type defines the generator, currently only "random" which generates a
# base58-encoded string of length bytes.
# type specifies which generator to use:
# - "random" which generates a base58-encoded string of $length bytes.
# - "wordlist" picks $length words from $file where $file should contain
# one word per line.
type: "random"
# length is the ID length.
# - For a "random" type, this is the byte length, resulting in
# - For the "random" type, this is the byte length, resulting in
# 2^($length * 8) possible combinations.
# - For the "wordlist" type, this is the amount of words, resulting in
# $wordlist_length^$length possible combinations.
length: 8
# file is used as the source for type "wordlist".
# file: "/usr/share/dict/words"


# The webserver section describes the web server's configuration.
Expand Down
8 changes: 8 additions & 0 deletions gosh_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func mainStore(conf Config) {
case "random":
idGenerator = randomIdGenerator(conf.Store.IdGenerator.Length)

case "wordlist":
var err error
idGenerator, err = wordlistIdGenerator(conf.Store.IdGenerator.File, conf.Store.IdGenerator.Length)
if err != nil {
slog.Error("Failed to create wordlist ID generator", slog.Any("error", err))
os.Exit(1)
}

default:
slog.Error("Failed to configure an ID generator as the type is unknown",
slog.String("type", conf.Store.IdGenerator.Type))
Expand Down
36 changes: 36 additions & 0 deletions store.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package main

import (
"bufio"
"crypto/rand"
"errors"
"fmt"
"io"
"log/slog"
"math/big"
"os"
"path/filepath"
"strings"
"time"

"github.com/akamensky/base58"
Expand Down Expand Up @@ -60,6 +63,39 @@ func randomIdGenerator(length int) func() (string, error) {
}
}

// wordlistIdGenerator returns an ID generator for the "wordlist" type.
func wordlistIdGenerator(sourceFile string, length int) (func() (string, error), error) {
f, err := os.Open(sourceFile)
if err != nil {
return nil, err
}
defer func() { _ = f.Close() }()

scanner := bufio.NewScanner(f)

words := make([]string, 0, 1024)
for scanner.Scan() {
words = append(words, scanner.Text())
}
err = scanner.Err()
if err != nil {
return nil, err
}

return func() (string, error) {
parts := make([]string, length)
for i := 0; i < length; i++ {
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(words))))
if err != nil {
return "", err
}
parts[i] = words[int(n.Int64())]
}

return strings.Join(parts, "-"), nil
}, nil
}

// Store stores an index of all Items as well as the pure files.
type Store struct {
baseDir string
Expand Down

0 comments on commit a33a40e

Please sign in to comment.