Made memory-based sessions work correctly, add a proof-of-work captcha to deter spamming
This commit is contained in:
parent
55bec8e5f8
commit
0a22d2fd39
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module hectabit.org/burgernotes
|
||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/catalinc/hashcash v1.0.0
|
||||||
github.com/gin-contrib/sessions v1.0.1
|
github.com/gin-contrib/sessions v1.0.1
|
||||||
github.com/gin-gonic/gin v1.10.0
|
github.com/gin-gonic/gin v1.10.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.22
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -2,6 +2,8 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc
|
||||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/catalinc/hashcash v1.0.0 h1:DiI2kBNCczy7y3xJnLddIl7KGx0yP4B7irFZZ+yzzwc=
|
||||||
|
github.com/catalinc/hashcash v1.0.0/go.mod h1:ldWL6buwYCK4VqIkLbZuFbGUoJceSafm8duCEQYw9Jw=
|
||||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
|
63
main.go
63
main.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/catalinc/hashcash"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -24,6 +25,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
conn *sql.DB
|
conn *sql.DB
|
||||||
|
mem *sql.DB
|
||||||
host string
|
host string
|
||||||
port int
|
port int
|
||||||
secretKey string
|
secretKey string
|
||||||
|
@ -133,7 +135,7 @@ func checkUsernameTaken(username string) (int, bool, error) {
|
||||||
func getSession(session string) (int, int, error) {
|
func getSession(session string) (int, int, error) {
|
||||||
var id int
|
var id int
|
||||||
var sessionId int
|
var sessionId int
|
||||||
err := conn.QueryRow("SELECT sessionid, id FROM sessions WHERE session = ? LIMIT 1", session).Scan(&sessionId, &id)
|
err := mem.QueryRow("SELECT sessionid, id FROM sessions WHERE session = ? LIMIT 1", session).Scan(&sessionId, &id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
|
@ -143,7 +145,7 @@ func getSession(session string) (int, int, error) {
|
||||||
func getSessionFromId(sessionId int) (string, int, error) {
|
func getSessionFromId(sessionId int) (string, int, error) {
|
||||||
var id int
|
var id int
|
||||||
var session string
|
var session string
|
||||||
err := conn.QueryRow("SELECT session, id FROM sessions WHERE sessionid = ? LIMIT 1", sessionId).Scan(&session, &id)
|
err := mem.QueryRow("SELECT session, id FROM sessions WHERE sessionid = ? LIMIT 1", sessionId).Scan(&session, &id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
|
@ -208,11 +210,22 @@ func migrateDb() {
|
||||||
if strings.ToLower(answer) == "y" {
|
if strings.ToLower(answer) == "y" {
|
||||||
_, err = conn.Exec("ALTER TABLE users DROP COLUMN versionTwoLegacyPassword")
|
_, err = conn.Exec("ALTER TABLE users DROP COLUMN versionTwoLegacyPassword")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[WARN] Unknown while migrating database (1/2):", err)
|
log.Println("[WARN] Unknown while migrating database (1/3):", err)
|
||||||
log.Println("[INFO] This is likely because your database is already migrated. This is not a problem, and Burgernotes does not need this removed - it is just for cleanup")
|
log.Println("[INFO] This is likely because your database is already migrated. This is not a problem, and Burgernotes does not need this removed - it is just for cleanup")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = conn.Exec("CREATE TABLE oauth (id INTEGER NOT NULL, oauthProvider TEXT NOT NULL, encryptedPasswd TEXT NOT NULL)")
|
_, err = conn.Exec("CREATE TABLE oauth (id INTEGER NOT NULL, oauthProvider TEXT NOT NULL, encryptedPasswd TEXT NOT NULL)")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[WARN] Unknown while migrating database (2/3):", err)
|
||||||
|
log.Println("[INFO] This is likely because your database is already migrated. This is not a problem, but if it is not, it may cause issues with OAuth2")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = conn.Exec("DROP TABLE sessions")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[WARN] Unknown while migrating database (3/3):", err)
|
||||||
|
log.Println("[INFO] This is likely because your database is already migrated. This is not a problem, and Burgernotes does not need this removed - it is just for cleanup")
|
||||||
|
return
|
||||||
|
}
|
||||||
} else if answer == ":3" {
|
} else if answer == ":3" {
|
||||||
log.Println("[:3] :3")
|
log.Println("[:3] :3")
|
||||||
} else {
|
} else {
|
||||||
|
@ -269,10 +282,30 @@ func main() {
|
||||||
defer func(conn *sql.DB) {
|
defer func(conn *sql.DB) {
|
||||||
err := conn.Close()
|
err := conn.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ERROR] Unknown in main() defer:", err)
|
log.Println("[ERROR] Unknown in main() conn defer:", err)
|
||||||
}
|
}
|
||||||
}(conn)
|
}(conn)
|
||||||
|
|
||||||
|
mem, err = sql.Open("sqlite3", ":memory: cache=shared")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("[FATAL] Cannot open session database:", err)
|
||||||
|
}
|
||||||
|
defer func(mem *sql.DB) {
|
||||||
|
err := mem.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[ERROR] Unknown in main() mem defer:", err)
|
||||||
|
}
|
||||||
|
}(mem)
|
||||||
|
|
||||||
|
_, err = mem.Exec("CREATE TABLE sessions (sessionid INTEGER PRIMARY KEY AUTOINCREMENT, session TEXT NOT NULL, id INTEGER NOT NULL, device TEXT NOT NULL DEFAULT '?')")
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "table sessions already exists" {
|
||||||
|
log.Println("[INFO] Session table already exists")
|
||||||
|
} else {
|
||||||
|
log.Fatalln("[FATAL] Cannot create session table:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
if os.Args[1] == "init_db" {
|
if os.Args[1] == "init_db" {
|
||||||
initDb()
|
initDb()
|
||||||
|
@ -327,6 +360,18 @@ func main() {
|
||||||
c.JSON(400, gin.H{"error": "Invalid JSON"})
|
c.JSON(400, gin.H{"error": "Invalid JSON"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
stamp, ok := data["stamp"].(string)
|
||||||
|
if !ok {
|
||||||
|
c.JSON(400, gin.H{"error": "Invalid JSON"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pow := hashcash.New(20, 16, "I love burgernotes!")
|
||||||
|
ok = pow.Check(stamp)
|
||||||
|
if !ok {
|
||||||
|
c.JSON(400, gin.H{"error": "Invalid hashcash stamp"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if username == "" || password == "" || len(username) > 20 || !regexp.MustCompile("^[a-zA-Z0-9]+$").MatchString(username) {
|
if username == "" || password == "" || len(username) > 20 || !regexp.MustCompile("^[a-zA-Z0-9]+$").MatchString(username) {
|
||||||
c.JSON(422, gin.H{"error": "Invalid username or password"})
|
c.JSON(422, gin.H{"error": "Invalid username or password"})
|
||||||
|
@ -379,7 +424,7 @@ func main() {
|
||||||
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SIGNUP-SESSIONSALT"})
|
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SIGNUP-SESSIONSALT"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = conn.Exec("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", token, userid, c.Request.Header.Get("User-Agent"))
|
_, err = mem.Exec("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", token, userid, c.Request.Header.Get("User-Agent"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ERROR] Unknown in /api/signup session Exec():", err)
|
log.Println("[ERROR] Unknown in /api/signup session Exec():", err)
|
||||||
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SIGNUP-SESSIONINSERT"})
|
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SIGNUP-SESSIONINSERT"})
|
||||||
|
@ -448,7 +493,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Exec("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", token, userid, c.Request.Header.Get("User-Agent"))
|
_, err = mem.Exec("INSERT INTO sessions (session, id, device) VALUES (?, ?, ?)", token, userid, c.Request.Header.Get("User-Agent"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ERROR] Unknown in /api/login session Exec():", err)
|
log.Println("[ERROR] Unknown in /api/login session Exec():", err)
|
||||||
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-LOGIN-SESSIONINSERT"})
|
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-LOGIN-SESSIONINSERT"})
|
||||||
|
@ -1121,7 +1166,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Exec("DELETE FROM sessions WHERE id = ?", userid)
|
_, err = mem.Exec("DELETE FROM sessions WHERE id = ?", userid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ERROR] Unknown in /api/deleteaccount session Exec():", err)
|
log.Println("[ERROR] Unknown in /api/deleteaccount session Exec():", err)
|
||||||
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-DELETEACCOUNT-SESSIONDELETE"})
|
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-DELETEACCOUNT-SESSIONDELETE"})
|
||||||
|
@ -1151,7 +1196,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := conn.Query("SELECT sessionid, session, device FROM sessions WHERE id = ? ORDER BY id DESC", userid)
|
rows, err := mem.Query("SELECT sessionid, session, device FROM sessions WHERE id = ? ORDER BY id DESC", userid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
c.JSON(200, []map[string]interface{}{})
|
c.JSON(200, []map[string]interface{}{})
|
||||||
|
@ -1236,7 +1281,7 @@ func main() {
|
||||||
c.JSON(403, gin.H{"error": "Session does not belong to user"})
|
c.JSON(403, gin.H{"error": "Session does not belong to user"})
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
_, err := conn.Exec("DELETE FROM sessions WHERE sessionid = ?", sessionId)
|
_, err := mem.Exec("DELETE FROM sessions WHERE sessionid = ?", sessionId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[ERROR] Unknown in /api/sessions/remove Exec():", err)
|
log.Println("[ERROR] Unknown in /api/sessions/remove Exec():", err)
|
||||||
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SESSIONS-REMOVE-DBDELETE"})
|
c.JSON(500, gin.H{"error": "Something went wrong on our end. Please report this bug at https://centrifuge.hectabit.org/hectabit/burgernotes and refer to the documentation for more info. Your error code is: UNKNOWN-API-SESSIONS-REMOVE-DBDELETE"})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
DROP TABLE IF EXISTS users;
|
DROP TABLE IF EXISTS users;
|
||||||
DROP TABLE IF EXISTS notes;
|
DROP TABLE IF EXISTS notes;
|
||||||
DROP TABLE IF EXISTS sessions;
|
DROP TABLE IF EXISTS oauth;
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
@ -18,13 +18,6 @@ CREATE TABLE notes (
|
||||||
title TEXT NOT NULL
|
title TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE sessions (
|
|
||||||
sessionid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
session TEXT NOT NULL,
|
|
||||||
id INTEGER NOT NULL,
|
|
||||||
device TEXT NOT NULL DEFAULT '?'
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE oauth (
|
CREATE TABLE oauth (
|
||||||
id INTEGER NOT NULL,
|
id INTEGER NOT NULL,
|
||||||
oauthProvider TEXT NOT NULL,
|
oauthProvider TEXT NOT NULL,
|
||||||
|
|
Loading…
Reference in New Issue