Skip to content

Commit 113d459

Browse files
author
Jon Staab
committed
Refactor everything, add invite codes
1 parent f259932 commit 113d459

File tree

14 files changed

+446
-277
lines changed

14 files changed

+446
-277
lines changed

.env.template

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ PORT=3334
22
RELAY_URL=
33
RELAY_NAME=
44
RELAY_ICON=
5-
RELAY_PUBKEY=
5+
RELAY_ADMIN=
6+
RELAY_SECRET=
67
RELAY_DESCRIPTION=
78
RELAY_CLAIMS=
89
AUTH_BACKEND=
910
AUTH_WHITELIST=
1011
AUTH_RESTRICT_USER=true
1112
AUTH_RESTRICT_AUTHOR=false
13+
GENERATE_CLAIMS=false

.fdignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ COPY go.mod go.sum ./
77
RUN go mod download
88

99
COPY *.go ./
10+
COPY common common
1011

1112
RUN CGO_ENABLED=0 GOOS=linux go build -o /frith
1213

acl.go

Lines changed: 0 additions & 124 deletions
This file was deleted.

cmd/dump/main.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"frith/common"
8+
"github.com/dgraph-io/badger/v4"
9+
_ "github.com/joho/godotenv/autoload"
10+
)
11+
12+
func main() {
13+
common.SetupEnvironment()
14+
common.SetupDatabase()
15+
16+
defer common.Db.Close()
17+
18+
err := common.Db.View(func(txn *badger.Txn) error {
19+
opts := badger.DefaultIteratorOptions
20+
it := txn.NewIterator(opts)
21+
defer it.Close()
22+
23+
for it.Rewind(); it.Valid(); it.Next() {
24+
item := it.Item()
25+
key := item.Key()
26+
27+
err := item.Value(func(val []byte) error {
28+
fmt.Printf("%s\t%s\n", key, string(val))
29+
return nil
30+
})
31+
32+
if err != nil {
33+
return err
34+
}
35+
}
36+
return nil
37+
})
38+
39+
if err != nil {
40+
log.Fatal("Error reading database:", err)
41+
}
42+
}

common/acl.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"slices"
7+
"sync"
8+
"time"
9+
)
10+
11+
func HasAccess(pubkey string) bool {
12+
return HasAccessUsingWhitelist(pubkey) || HasAccessUsingClaim(pubkey) || HasAccessUsingBackend(pubkey)
13+
}
14+
15+
func HasAccessUsingWhitelist(pubkey string) bool {
16+
return slices.Contains(AUTH_WHITELIST, pubkey)
17+
}
18+
19+
func HasAccessUsingClaim(pubkey string) bool {
20+
return len(getUserClaims(pubkey)) > 0
21+
}
22+
23+
type BackendAccess struct {
24+
granted bool
25+
expires time.Time
26+
}
27+
28+
var backend_acl = make(map[string]BackendAccess)
29+
var backend_acl_mu sync.Mutex
30+
31+
func HasAccessUsingBackend(pubkey string) bool {
32+
backend_acl_mu.Lock()
33+
defer backend_acl_mu.Unlock()
34+
35+
// If we don't have a backend, we're done
36+
if AUTH_BACKEND == "" {
37+
return false
38+
}
39+
40+
// If we have an un-expired entry, use it
41+
if access, ok := backend_acl[pubkey]; ok && access.expires.After(time.Now()) {
42+
return access.granted
43+
}
44+
45+
// Fetch the url
46+
res, err := http.Get(fmt.Sprintf("%s%s", AUTH_BACKEND, pubkey))
47+
48+
// If we get a 200, consider it good
49+
if err == nil {
50+
expire_after, _ := time.ParseDuration("1m")
51+
52+
backend_acl[pubkey] = BackendAccess{
53+
granted: res.StatusCode == 200,
54+
expires: time.Now().Add(expire_after),
55+
}
56+
} else {
57+
fmt.Println(err)
58+
}
59+
60+
return backend_acl[pubkey].granted
61+
}

common/claim.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package common
2+
3+
import (
4+
"slices"
5+
"strings"
6+
)
7+
8+
func isValidClaim(claim string) bool {
9+
return slices.Contains(RELAY_CLAIMS, claim)
10+
}
11+
12+
func getUserClaims(pubkey string) []string {
13+
return split(GetItem("claim", pubkey), ",")
14+
}
15+
16+
func addUserClaim(pubkey string, claim string) {
17+
claims := getUserClaims(pubkey)
18+
19+
if !slices.Contains(claims, claim) {
20+
claims = append(claims, claim)
21+
22+
PutItem("claim", pubkey, strings.Join(claims, ","))
23+
}
24+
}

common/db.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"github.com/dgraph-io/badger/v4"
7+
)
8+
9+
var Db *badger.DB
10+
11+
func SetupDatabase() {
12+
var err error
13+
Db, err = badger.Open(badger.DefaultOptions(GetDataDir("frith")))
14+
if err != nil {
15+
log.Fatal("Failed to open badger db:", err)
16+
}
17+
}
18+
19+
func PutItem(tbl string, key string, value string) {
20+
if err := Db.Update(func(txn *badger.Txn) error {
21+
return txn.Set([]byte(tbl+":"+key), []byte(value))
22+
}); err != nil {
23+
fmt.Println(err)
24+
}
25+
}
26+
27+
func GetItem(tbl string, key string) string {
28+
var result string
29+
err := Db.View(func(txn *badger.Txn) error {
30+
item, err := txn.Get([]byte(tbl + ":" + key))
31+
if err != nil {
32+
return err
33+
}
34+
35+
return item.Value(func(val []byte) error {
36+
result = string(val)
37+
return nil
38+
})
39+
})
40+
41+
if err != nil && err != badger.ErrKeyNotFound {
42+
fmt.Println(err)
43+
}
44+
45+
return result
46+
}
47+
48+
func DeleteItem(tbl string, key string) {
49+
err := Db.Update(func(txn *badger.Txn) error {
50+
return txn.Delete([]byte(tbl + ":" + key))
51+
})
52+
if err != nil {
53+
fmt.Println(err)
54+
}
55+
}

common/env.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
_ "github.com/joho/godotenv/autoload"
6+
"github.com/nbd-wtf/go-nostr"
7+
"os"
8+
"strings"
9+
)
10+
11+
var PORT string
12+
var RELAY_URL string
13+
var RELAY_NAME string
14+
var RELAY_ICON string
15+
var RELAY_ADMIN string
16+
var RELAY_SECRET string
17+
var RELAY_SELF string
18+
var RELAY_DESCRIPTION string
19+
var RELAY_CLAIMS []string
20+
var AUTH_BACKEND string
21+
var AUTH_WHITELIST []string
22+
var AUTH_RESTRICT_USER bool
23+
var AUTH_RESTRICT_AUTHOR bool
24+
var GENERATE_CLAIMS bool
25+
var DATA_DIR string
26+
27+
func SetupEnvironment() {
28+
var env = make(map[string]string)
29+
30+
for _, item := range os.Environ() {
31+
parts := strings.SplitN(item, "=", 2)
32+
env[parts[0]] = parts[1]
33+
}
34+
35+
getEnv := func(k string, fallback ...string) (v string) {
36+
v = env[k]
37+
38+
if v == "" && len(fallback) > 0 {
39+
v = fallback[0]
40+
}
41+
42+
return v
43+
}
44+
45+
PORT = getEnv("PORT", "3334")
46+
RELAY_URL = getEnv("RELAY_URL", "localhost:3334")
47+
RELAY_NAME = getEnv("RELAY_NAME", "Frith")
48+
RELAY_ICON = getEnv("RELAY_ICON", "https://hbr.coracle.social/fd73de98153b615f516d316d663b413205fd2e6e53d2c6064030ab57a7685bbd.jpg")
49+
RELAY_ADMIN = getEnv("RELAY_ADMIN", "")
50+
RELAY_SECRET = getEnv("RELAY_SECRET", nostr.GeneratePrivateKey())
51+
RELAY_SELF, _ = nostr.GetPublicKey(RELAY_SECRET)
52+
RELAY_DESCRIPTION = getEnv("RELAY_DESCRIPTION", "A nostr relay for hosting groups.")
53+
RELAY_CLAIMS = split(getEnv("RELAY_CLAIMS", ""), ",")
54+
AUTH_BACKEND = getEnv("AUTH_BACKEND", "")
55+
AUTH_WHITELIST = split(getEnv("AUTH_WHITELIST", ""), ",")
56+
AUTH_RESTRICT_USER = getEnv("AUTH_RESTRICT_USER", "true") == "true"
57+
AUTH_RESTRICT_AUTHOR = getEnv("AUTH_RESTRICT_AUTHOR", "false") == "true"
58+
GENERATE_CLAIMS = getEnv("GENERATE_CLAIMS", "false") == "true"
59+
DATA_DIR = getEnv("DATA_DIR", "./data")
60+
}
61+
62+
func GetDataDir(dir string) string {
63+
return fmt.Sprintf("%s/%s", DATA_DIR, dir)
64+
}

0 commit comments

Comments
 (0)