aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db.go16
-rw-r--r--fbfp.scfg.example10
-rw-r--r--go.mod8
-rw-r--r--go.sum28
-rw-r--r--index.go99
-rw-r--r--main.go42
-rw-r--r--oidc.go55
-rw-r--r--schema.sql4
8 files changed, 198 insertions, 64 deletions
diff --git a/db.go b/db.go
index 470f9e5..830bc0c 100644
--- a/db.go
+++ b/db.go
@@ -1,19 +1,19 @@
package main
import (
- "database/sql"
+ "context"
+ "errors"
- _ "github.com/mattn/go-sqlite3"
+ "github.com/jackc/pgx/v5/pgxpool"
)
-var db *sql.DB
+var db *pgxpool.Pool
func setup_database() error {
var err error
- db, err = sql.Open(config.Db.Type, config.Db.Conn)
- if err != nil {
- return err
- } else {
- return nil
+ if config.Db.Type != "postgres" {
+ return errors.New("At the moment, the only supported database type is postgres")
}
+ db, err = pgxpool.New(context.Background(), config.Db.Conn)
+ return err
}
diff --git a/fbfp.scfg.example b/fbfp.scfg.example
index e21cca1..f00cfba 100644
--- a/fbfp.scfg.example
+++ b/fbfp.scfg.example
@@ -35,13 +35,13 @@ listen {
}
db {
- # What type of database should we use? Currently, only "sqlite" is
+ # What type of database should we use? Currently, only "postgres" is
# supported.
- type sqlite3
+ type postgres
- # What is the connection string to database? For SQLite, this is
- # simply a path to the database file.
- conn test.db
+ # What is the connection string to database?
+ # Example: postgresql:///fbfp?host=/var/run/postgresql
+ conn postgresql:///fbfp?host=/var/run/postgresql
}
openid {
diff --git a/go.mod b/go.mod
index ef7c087..e044430 100644
--- a/go.mod
+++ b/go.mod
@@ -7,10 +7,16 @@ require git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082
require (
github.com/MicahParks/keyfunc/v3 v3.3.3
github.com/golang-jwt/jwt/v5 v5.2.1
- github.com/mattn/go-sqlite3 v1.14.22
+ github.com/jackc/pgx/v5 v5.6.0
)
require (
github.com/MicahParks/jwkset v0.5.18 // indirect
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
+ github.com/jackc/puddle/v2 v2.2.1 // indirect
+ golang.org/x/crypto v0.26.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
)
diff --git a/go.sum b/go.sum
index d541d1d..5b6ed08 100644
--- a/go.sum
+++ b/go.sum
@@ -4,11 +4,35 @@ github.com/MicahParks/jwkset v0.5.18 h1:WLdyMngF7rCrnstQxA7mpRoxeaWqGzPM/0z40PJU
github.com/MicahParks/jwkset v0.5.18/go.mod h1:q8ptTGn/Z9c4MwbcfeCDssADeVQb3Pk7PnVxrvi+2QY=
github.com/MicahParks/keyfunc/v3 v3.3.3 h1:c6j9oSu1YUo0k//KwF1miIQlEMtqNlj7XBFLB8jtEmY=
github.com/MicahParks/keyfunc/v3 v3.3.3/go.mod h1:f/UMyXdKfkZzmBeBFUeYk+zu066J1Fcl48f7Wnl5Z48=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
-github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
-github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
+github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/index.go b/index.go
new file mode 100644
index 0000000..9b53b6c
--- /dev/null
+++ b/index.go
@@ -0,0 +1,99 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/jackc/pgx/v5"
+)
+
+func handle_index(w http.ResponseWriter, req *http.Request) {
+ session_cookie, err := req.Cookie("session")
+ if errors.Is(err, http.ErrNoCookie) {
+ err = tmpl.ExecuteTemplate(
+ w,
+ "index_login",
+ map[string]string{
+ "authUrl": generate_authorization_url(),
+ },
+ )
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ return
+ } else if err != nil {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(400)
+ w.Write([]byte(fmt.Sprintf(
+ "Error\n" +
+ "Unable to check cookie.",
+ )))
+ return
+ }
+ var userid string
+ var expr int
+ err = db.QueryRow(context.Background(), "SELECT userid, expr FROM sessions WHERE cookie = $1", session_cookie.Value).Scan(&userid, &expr)
+ if err != nil {
+ if errors.Is(err, pgx.ErrNoRows) {
+ err = tmpl.ExecuteTemplate(
+ w,
+ "index_login",
+ map[string]interface{}{
+ "authUrl": generate_authorization_url(),
+ "notes": []string{"Technically you have a session cookie, but it seems invalid."},
+ },
+ )
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ return
+ } else {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf(
+ "Error\nUnexpected database error.\n%s\n",
+ err,
+ )))
+ return
+ }
+ }
+ var name string
+ err = db.QueryRow(context.Background(), "SELECT name FROM users WHERE id = $1", userid).Scan(&name)
+ if err != nil {
+ if errors.Is(err, pgx.ErrNoRows) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf(
+ "Error\nYour user doesn't exist. (This looks like a data integrity error.)\n%s\n",
+ err,
+ )))
+ return
+ } else {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf(
+ "Error\nUnexpected database error.\n%s\n",
+ err,
+ )))
+ return
+ }
+ }
+ err = tmpl.ExecuteTemplate(
+ w,
+ "index",
+ map[string]interface{}{
+ "user": map[string]interface{}{
+ "Name": name,
+ },
+ },
+ )
+ if err != nil {
+ log.Println(err)
+ return
+ }
+}
diff --git a/main.go b/main.go
index c494cb2..907ab26 100644
--- a/main.go
+++ b/main.go
@@ -21,8 +21,6 @@
package main
import (
- "errors"
- "fmt"
"html/template"
"log"
"net"
@@ -32,46 +30,6 @@ import (
var tmpl *template.Template
-func handle_index(w http.ResponseWriter, req *http.Request) {
- session_cookie, err := req.Cookie("session")
- if errors.Is(err, http.ErrNoCookie) {
- err = tmpl.ExecuteTemplate(
- w,
- "index_login",
- map[string]string{
- "authUrl": generate_authorization_url(),
- },
- )
- if err != nil {
- log.Println(err)
- return
- }
- return
- } else if err != nil {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(400)
- w.Write([]byte(fmt.Sprintf(
- "Error\n" +
- "Unable to check cookie.",
- )))
- return
- }
- err = tmpl.ExecuteTemplate(
- w,
- "index",
- map[string]interface{}{
- "user": map[string]interface{}{
- "Name": "NAME",
- },
- },
- )
- if err != nil {
- log.Println(err)
- return
- }
- _ = session_cookie
-}
-
func main() {
/*
* This seems necessary because in the following sections I need to
diff --git a/oidc.go b/oidc.go
index add2242..004efdd 100644
--- a/oidc.go
+++ b/oidc.go
@@ -21,6 +21,7 @@
package main
import (
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -30,6 +31,7 @@ import (
"github.com/MicahParks/keyfunc/v3"
"github.com/golang-jwt/jwt/v5"
+ "github.com/jackc/pgx/v5/pgconn"
)
var openid_configuration struct {
@@ -246,15 +248,60 @@ func handle_oidc(w http.ResponseWriter, req *http.Request) {
http.SetCookie(w, &cookie)
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- result, err := db.Exec(
- "INSERT INTO users (id, name, email) VALUES (?, ?, ?)",
+ _, err = db.Exec(
+ context.Background(),
+ "INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
claims.Subject,
claims.Name,
claims.Email,
)
- // TODO: handle err
+ if err != nil {
+ var pgErr *pgconn.PgError
+ if errors.As(err, &pgErr) {
+ if pgErr.Code == "23505" {
+ _, err := db.Exec(
+ context.Background(),
+ "UPDATE users SET (name, email) = ($1, $2) WHERE id = $3",
+ claims.Name,
+ claims.Email,
+ claims.Subject,
+ )
+ if err != nil {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf("Error\nDatabase error while updating your account.\n%s\n", err)))
+ return
+ }
+ }
+ } else {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf("Error\nDatabase error while attempting to insert account info.\n%s\n", err)))
+ return
+ }
+ }
- fmt.Println(result, err)
+ _, err = db.Exec(
+ context.Background(),
+ "INSERT INTO sessions(userid, cookie, expr) VALUES ($1, $2, $3)",
+ claims.Subject,
+ cookie_value,
+ 1881839332, /* TODO */
+ )
+ if err != nil {
+ var pgErr *pgconn.PgError
+ if errors.As(err, &pgErr) && pgErr.Code == "23505" {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf("Error\nCookie collision! Could you try signing in again?\n%s\n", err)))
+ return
+ } else {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(500)
+ w.Write([]byte(fmt.Sprintf("Error\nDatabase error while attempting to insert session info.\n%s\n", err)))
+ return
+ }
+ }
http.Redirect(w, req, "/", 303)
diff --git a/schema.sql b/schema.sql
index 7e3886f..192b4ad 100644
--- a/schema.sql
+++ b/schema.sql
@@ -5,7 +5,7 @@ CREATE TABLE users (
);
CREATE TABLE sessions (
userid TEXT NOT NULL,
- cookie TEXT,
- expr INTEGER,
+ cookie TEXT PRIMARY KEY NOT NULL,
+ expr INTEGER NOT NULL,
FOREIGN KEY(userid) REFERENCES users(id)
);