diff --git a/account/addtoken.go b/account/addtoken.go
new file mode 100644
index 0000000..1c36ad8
--- /dev/null
+++ b/account/addtoken.go
@@ -0,0 +1,56 @@
+package account
+
+import (
+ "log"
+ "time"
+
+ "tildegit.org/andinus/perseus/password"
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// addToken will generate a random token, add it to database and
+// return the token.
+func (u *User) addToken(db *storage.DB) error {
+ u.Token = password.RandStr(64)
+
+ // Set user id from username.
+ err := u.GetID(db)
+ if err != nil {
+ log.Printf("account/addtoken.go: %s\n",
+ "failed to get id from username")
+ return err
+ }
+
+ // Acquire write lock on the database.
+ db.Mu.Lock()
+ defer db.Mu.Unlock()
+
+ // Start the transaction
+ tx, err := db.Conn.Begin()
+ defer tx.Rollback()
+ if err != nil {
+ log.Printf("account/addtoken.go: %s\n",
+ "failed to begin transaction")
+ return err
+ }
+
+ stmt, err := db.Conn.Prepare(`
+INSERT INTO access(id, token, genTime) values(?, ?, ?)`)
+ if err != nil {
+ log.Printf("account/addtoken.go: %s\n",
+ "failed to prepare statement")
+ return err
+ }
+ defer stmt.Close()
+
+ _, err = stmt.Exec(u.ID, u.Token, time.Now().UTC())
+ if err != nil {
+ log.Printf("account/addtoken.go: %s\n",
+ "failed to execute statement")
+ return err
+ }
+
+ tx.Commit()
+ return err
+
+}
diff --git a/account/adduser.go b/account/adduser.go
new file mode 100644
index 0000000..8a8734f
--- /dev/null
+++ b/account/adduser.go
@@ -0,0 +1,43 @@
+package account
+
+import (
+ "log"
+ "time"
+
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// addUser adds the user to record.
+func (u *User) addUser(db *storage.DB) error {
+ // Acquire write lock on the database.
+ db.Mu.Lock()
+ defer db.Mu.Unlock()
+
+ // Start the transaction
+ tx, err := db.Conn.Begin()
+ defer tx.Rollback()
+ if err != nil {
+ log.Printf("account/adduser.go: %s\n",
+ "failed to begin transaction")
+ return err
+ }
+
+ stmt, err := db.Conn.Prepare(`
+INSERT INTO accounts(id, username, hash, regTime) values(?, ?, ?, ?)`)
+ if err != nil {
+ log.Printf("account/adduser.go: %s\n",
+ "failed to prepare statement")
+ return err
+ }
+ defer stmt.Close()
+
+ _, err = stmt.Exec(u.ID, u.Username, u.Hash, time.Now().UTC())
+ if err != nil {
+ log.Printf("account/adduser.go: %s\n",
+ "failed to execute statement")
+ return err
+ }
+
+ tx.Commit()
+ return err
+}
diff --git a/account/getid.go b/account/getid.go
new file mode 100644
index 0000000..4f6da69
--- /dev/null
+++ b/account/getid.go
@@ -0,0 +1,33 @@
+package account
+
+import (
+ "log"
+
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// GetID returns id from username.
+func (u *User) GetID(db *storage.DB) error {
+ // Acquire read lock on database.
+ db.Mu.RLock()
+ defer db.Mu.RUnlock()
+
+ // Get password for this user from the database.
+ stmt, err := db.Conn.Prepare("SELECT id FROM accounts WHERE username = ?")
+ if err != nil {
+ log.Printf("account/getid.go: %s\n",
+ "failed to prepare statement")
+ return err
+ }
+ defer stmt.Close()
+
+ var id string
+ err = stmt.QueryRow(u.Username).Scan(&id)
+ if err != nil {
+ log.Printf("account/getid.go: %s\n",
+ "query failed")
+ }
+ u.ID = id
+
+ return err
+}
diff --git a/account/login.go b/account/login.go
new file mode 100644
index 0000000..c81fcbd
--- /dev/null
+++ b/account/login.go
@@ -0,0 +1,50 @@
+package account
+
+import (
+ "log"
+
+ "tildegit.org/andinus/perseus/password"
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// Login takes in login details and returns an error. If error doesn't
+// equal nil then consider login failed. It will also set the u.Token
+// field.
+func (u *User) Login(db *storage.DB) error {
+ // Acquire read lock on the database.
+ db.Mu.RLock()
+
+ // Get password for this user from the database.
+ stmt, err := db.Conn.Prepare("SELECT hash FROM accounts WHERE username = ?")
+ if err != nil {
+ log.Printf("account/login.go: %s\n",
+ "failed to prepare statement")
+ return err
+ }
+ defer stmt.Close()
+
+ var hash string
+ err = stmt.QueryRow(u.Username).Scan(&hash)
+ if err != nil {
+ log.Printf("account/login.go: %s\n",
+ "query failed")
+ return err
+ }
+ u.Hash = hash
+
+ // Check user's password.
+ err = password.Check(u.Password, u.Hash)
+ if err != nil {
+ log.Printf("account/login.go: %s%s\n",
+ "user login failed, username: ", u.Username)
+ return err
+ }
+ db.Mu.RUnlock()
+
+ err = u.addToken(db)
+ if err != nil {
+ log.Printf("account/login.go: %s\n",
+ "addtoken failed")
+ }
+ return err
+}
diff --git a/account/register.go b/account/register.go
new file mode 100644
index 0000000..e008370
--- /dev/null
+++ b/account/register.go
@@ -0,0 +1,49 @@
+package account
+
+import (
+ "errors"
+ "log"
+ "regexp"
+ "strings"
+
+ "tildegit.org/andinus/perseus/password"
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// Register takes in registration details and returns an error. If
+// error doesn't equal nil then the registration was unsuccessful.
+func (u User) Register(db *storage.DB) error {
+ var err error
+ u.ID = password.RandStr(64)
+ u.Username = strings.ToLower(u.Username)
+
+ // Validate username. It must be alphanumeric and less than
+ // 128 characters.
+ re := regexp.MustCompile("^[a-zA-Z0-9]*$")
+ if !re.MatchString(u.Username) {
+ return errors.New("account/register.go: invalid username")
+ }
+ if len(u.Username) > 128 {
+ return errors.New("account/register.go: username too long")
+ }
+
+ // Validate password
+ if len(u.Password) < 8 {
+ return errors.New("account/register.go: password too short")
+ }
+
+ u.Hash, err = password.Hash(u.Password)
+ if err != nil {
+ log.Printf("account/register.go: %s\n",
+ "password.Hash func failed")
+ return err
+ }
+
+ err = u.addUser(db)
+ if err != nil {
+ log.Printf("account/register.go: %s\n",
+ "addUser func failed")
+ }
+ return err
+
+}
diff --git a/user/user.go b/account/user.go
similarity index 80%
rename from user/user.go
rename to account/user.go
index 078215e..769e8fc 100644
--- a/user/user.go
+++ b/account/user.go
@@ -1,4 +1,4 @@
-package user
+package account
// User holds information about the user.
type User struct {
@@ -6,4 +6,5 @@ type User struct {
Username string
Password string
Hash string
+ Token string
}
diff --git a/auth/genid.go b/auth/genid.go
deleted file mode 100644
index fea7ac9..0000000
--- a/auth/genid.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package auth
-
-import (
- "crypto/rand"
- "encoding/base64"
-)
-
-// genID generates a random id string of length n. Don't forget to
-// seed the random number generator otherwise it won't be random.
-func genID(n int) string {
- b := make([]byte, n/2)
- rand.Read(b)
- return base64.StdEncoding.EncodeToString(b)
-}
diff --git a/auth/hashpass.go b/auth/hashpass.go
deleted file mode 100644
index 4e5041a..0000000
--- a/auth/hashpass.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package auth
-
-import (
- "golang.org/x/crypto/bcrypt"
-)
-
-// hashPass takes a string as input and returns the hash of the
-// password.
-func hashPass(password string) (string, error) {
- // 10 is the default cost.
- bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)
- return string(bytes), err
-}
diff --git a/build/ci/drone.yml b/build/ci/drone.yml
index 6d68a3f..37590ac 100644
--- a/build/ci/drone.yml
+++ b/build/ci/drone.yml
@@ -6,12 +6,12 @@ steps:
- name: vet
image: golang:1.13
commands:
- - go vet ./...
+ - go vet ./...
- name: test
image: golang:1.13
commands:
- - go test -v ./auth
+ - go test -v ./password
---
kind: pipeline
@@ -24,4 +24,4 @@ steps:
GOARCH: amd64
GOOS: openbsd
commands:
- - go build ./cmd/perseus
+ - go build ./cmd/perseus
diff --git a/cmd/perseus/main.go b/cmd/perseus/main.go
index 6abd3a4..ca1a50d 100644
--- a/cmd/perseus/main.go
+++ b/cmd/perseus/main.go
@@ -15,25 +15,24 @@ func main() {
db := storage.Init()
defer db.Conn.Close()
- envPort, exists := os.LookupEnv("PERSEUS_PORT")
- if !exists {
+ envPort := os.Getenv("PERSEUS_PORT")
+ if envPort == "" {
envPort = "8080"
}
- addr := fmt.Sprintf("127.0.0.1:%s", envPort)
srv := &http.Server{
- Addr: addr,
+ Addr: fmt.Sprintf("127.0.0.1:%s", envPort),
WriteTimeout: 8 * time.Second,
ReadTimeout: 8 * time.Second,
}
http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
- web.HandleRegister(w, r, db)
+ web.RegisterHandler(w, r, db)
})
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
- web.HandleLogin(w, r, db)
+ web.LoginHandler(w, r, db)
})
- log.Printf("main/main.go: listening on port %s...", envPort)
+ log.Printf("perseus: listening on port %s...", envPort)
log.Fatal(srv.ListenAndServe())
}
diff --git a/core/version.go b/core/version.go
deleted file mode 100644
index 3e45c6f..0000000
--- a/core/version.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package core
-
-// Version will return the current version.
-func Version() string {
- return "v0.1.0"
-}
diff --git a/handler/web/login.go b/handler/web/login.go
new file mode 100644
index 0000000..3ad15a1
--- /dev/null
+++ b/handler/web/login.go
@@ -0,0 +1,81 @@
+package web
+
+import (
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+ "time"
+
+ "tildegit.org/andinus/perseus/account"
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// LoginHandler handles login.
+func LoginHandler(w http.ResponseWriter, r *http.Request, db *storage.DB) {
+ p := Page{}
+ var err error
+
+ t, err := template.ParseFiles("web/templates/login.html")
+ if err != nil {
+ log.Printf("web/login.go: 500 Internal Server Error :: %s", err.Error())
+ http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ switch r.Method {
+ case http.MethodGet:
+ t.Execute(w, p)
+
+ case http.MethodPost:
+ if err = r.ParseForm(); err != nil {
+ log.Printf("web/login.go: 400 Bad Request :: %s", err.Error())
+ http.Error(w, "400 Bad Request", http.StatusBadRequest)
+ return
+ }
+
+ // Get form values
+ u := account.User{}
+ u.Username = r.FormValue("username")
+ u.Password = r.FormValue("password")
+
+ // Perform login
+ err = u.Login(db)
+
+ if err != nil {
+ log.Printf("web/login.go: %s :: %s",
+ "login failed",
+ err.Error())
+
+ error := []string{}
+ error = append(error,
+ fmt.Sprintf("Login failed"))
+
+ p.Error = error
+ t.Execute(w, p)
+ return
+ }
+
+ // Login successful, set token
+ cookie := http.Cookie{
+ Name: "token",
+ Value: u.Token,
+ // Expire the cookie after 16 days from
+ // current UTC time.
+ Expires: time.Now().UTC().Add(16 * 24 * time.Hour),
+ SameSite: http.SameSiteLaxMode,
+ HttpOnly: true,
+ }
+ http.SetCookie(w, &cookie)
+ success := []string{}
+ success = append(success,
+ fmt.Sprintf("Login successful"))
+ p.Success = success
+ t.Execute(w, p)
+
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ log.Printf("web/login.go: %v not allowed on %v", r.Method, r.URL)
+ }
+
+}
diff --git a/handler/web/page.go b/handler/web/page.go
index 1f457de..91e8e56 100644
--- a/handler/web/page.go
+++ b/handler/web/page.go
@@ -1,11 +1,8 @@
package web
-import (
- "html/template"
-)
+import "html/template"
-// Page holds page information that is sent to all webpages rendered
-// by perseus.
+// Page holds page information.
type Page struct {
SafeList []template.HTML
List []string
diff --git a/handler/web/register.go b/handler/web/register.go
new file mode 100644
index 0000000..1a80651
--- /dev/null
+++ b/handler/web/register.go
@@ -0,0 +1,80 @@
+package web
+
+import (
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+ "strings"
+
+ "tildegit.org/andinus/perseus/account"
+ "tildegit.org/andinus/perseus/storage"
+)
+
+// RegisterHandler handles registration.
+func RegisterHandler(w http.ResponseWriter, r *http.Request, db *storage.DB) {
+ p := Page{}
+ var err error
+
+ t, err := template.ParseFiles("web/templates/register.html")
+ if err != nil {
+ log.Printf("web/register.go: 500 Internal Server Error :: %s", err.Error())
+ http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ p.Notice = []string{
+ "Only [a-z] & [0-9] allowed for username",
+ "Password length must be greater than 8 characters",
+ }
+
+ switch r.Method {
+ case http.MethodGet:
+ t.Execute(w, p)
+
+ case http.MethodPost:
+ if err = r.ParseForm(); err != nil {
+ log.Printf("web/register.go: 400 Bad Request :: %s", err.Error())
+ http.Error(w, "400 Bad Request", http.StatusBadRequest)
+ return
+ }
+
+ // Get form values
+ u := account.User{}
+ u.Username = r.FormValue("username")
+ u.Password = r.FormValue("password")
+
+ // Perform registration
+ err = u.Register(db)
+
+ if err != nil {
+ log.Printf("web/register.go: %s :: %s",
+ "registration failed",
+ err.Error())
+
+ error := []string{}
+ error = append(error,
+ fmt.Sprintf("Registration failed"))
+
+ // Check if the error was because of username
+ // not being unique.
+ if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") {
+ error = append(error,
+ fmt.Sprintf("Username not unique"))
+ }
+ p.Error = error
+ } else {
+ success := []string{}
+ success = append(success,
+ fmt.Sprintf("Registration successful"))
+ p.Success = success
+ }
+
+ t.Execute(w, p)
+
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ log.Printf("web/register.go: %v not allowed on %v", r.Method, r.URL)
+ }
+
+}
diff --git a/auth/checkpass.go b/password/check.go
similarity index 54%
rename from auth/checkpass.go
rename to password/check.go
index 64e3c9f..b84e9fe 100644
--- a/auth/checkpass.go
+++ b/password/check.go
@@ -1,14 +1,13 @@
-package auth
+// Password package contains functions related to passwords.
+package password
-import (
- "golang.org/x/crypto/bcrypt"
-)
+import "golang.org/x/crypto/bcrypt"
-// checkPass takes a string and hash as input and returns an error. If
+// Check takes a string and hash as input and returns an error. If
// the error is not nil then the consider the password wrong. We're
// returning error instead of a bool so that we can print failed
// logins to log and logging shouldn't happen here.
-func checkPass(password, hash string) error {
+func Check(password, hash string) error {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err
}
diff --git a/auth/checkpass_test.go b/password/check_test.go
similarity index 55%
rename from auth/checkpass_test.go
rename to password/check_test.go
index c8afaee..e55c169 100644
--- a/auth/checkpass_test.go
+++ b/password/check_test.go
@@ -1,9 +1,9 @@
-package auth
+package password
import "testing"
-// TestCheckPass tests the checkPass function.
-func TestCheckPass(t *testing.T) {
+// TestCheck tests the Check function.
+func TestCheck(t *testing.T) {
var err error
passhash := make(map[string]string)
@@ -13,24 +13,22 @@ func TestCheckPass(t *testing.T) {
passhash["Z1S/kQ=="] = "$2a$10$fZ05kKmb7bh4vBLebpK1u.3bUNQ6eeX5ghT/GZaekgS.5bx4.Ru1e"
passhash["J861dQ=="] = "$2a$10$nXb6Btn6n3AWMAUkDh9bFObvQw5V9FLKhfX.E1EzRWgVDuqIp99u2"
- // We also check with values generated with hashPass, this may
- // fail if hashPass itself fails in that case it's not
- // checkPass error so the test shouldn't fail but warning
- // should be sent. We use genID func to generate random inputs
- // for this test.
+ // We also check with values generated with Hash, this may
+ // fail if Hash itself fails in that case it's not Check error
+ // so the test shouldn't fail but warning should be sent. We
+ // use genID func to generate random inputs for this test.
for i := 1; i <= 4; i++ {
- p := genID(8)
- passhash[p], err = hashPass(p)
+ p := RandStr(8)
+ passhash[p], err = Hash(p)
if err != nil {
t.Log("hashPass func failed")
}
}
- // We test the checkPass func by ranging over all values of
- // passhash. We assume that hashPass func returns correct
- // hashes.
+ // We test the Check func by ranging over all values of
+ // passhash. We assume that Hash func returns correct hashes.
for p, h := range passhash {
- err = checkPass(p, h)
+ err = Check(p, h)
if err != nil {
t.Errorf("password: %s, hash: %s didn't match.",
p, h)
diff --git a/password/hash.go b/password/hash.go
new file mode 100644
index 0000000..3dd949b
--- /dev/null
+++ b/password/hash.go
@@ -0,0 +1,11 @@
+package password
+
+import "golang.org/x/crypto/bcrypt"
+
+// Hash takes a string as input and returns the hash of the
+// password.
+func Hash(password string) (string, error) {
+ // 10 is the default cost.
+ out, err := bcrypt.GenerateFromPassword([]byte(password), 10)
+ return string(out), err
+}
diff --git a/auth/hashpass_test.go b/password/hash_test.go
similarity index 58%
rename from auth/hashpass_test.go
rename to password/hash_test.go
index 7ea9480..4f37393 100644
--- a/auth/hashpass_test.go
+++ b/password/hash_test.go
@@ -1,21 +1,21 @@
-package auth
+package password
import "testing"
-// TestHashPass tests the checkPass function.
-func TestHashPass(t *testing.T) {
+// TestHash tests the Hash function.
+func TestHash(t *testing.T) {
var err error
passhash := make(map[string]string)
- // We generate random hashes with hashPass, random string is
- // generate by genID func.
+ // We generate random hashes with Hash, random string is
+ // generate by RandStr func.
for i := 1; i <= 8; i++ {
- p := genID(8)
- passhash[p], err = hashPass(p)
+ p := RandStr(8)
+ passhash[p], err = Hash(p)
// Here we test if the hashPass func runs sucessfully.
if err != nil {
- t.Errorf("hashPass func failed for password: %s",
+ t.Errorf("Hash func failed for password: %s",
p)
}
}
@@ -24,7 +24,7 @@ func TestHashPass(t *testing.T) {
// hashes. We assume that checkPass func returns correct
// values.
for p, h := range passhash {
- err = checkPass(p, h)
+ err = Check(p, h)
if err != nil {
t.Errorf("password: %s, hash: %s didn't match.",
p, h)
diff --git a/password/randstr.go b/password/randstr.go
new file mode 100644
index 0000000..86ae9a1
--- /dev/null
+++ b/password/randstr.go
@@ -0,0 +1,13 @@
+package password
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+)
+
+// RandStr will return a random base64 encoded string of length n.
+func RandStr(n int) string {
+ b := make([]byte, n/2)
+ rand.Read(b)
+ return base64.StdEncoding.EncodeToString(b)
+}
diff --git a/storage/sqlite3/init.go b/storage/init.go
similarity index 88%
rename from storage/sqlite3/init.go
rename to storage/init.go
index e79d3ff..2103498 100644
--- a/storage/sqlite3/init.go
+++ b/storage/init.go
@@ -1,4 +1,4 @@
-package sqlite3
+package storage
import (
"database/sql"
@@ -17,8 +17,7 @@ func initErr(db *DB, err error) {
log.Fatalf("Initialization Error :: %s", err.Error())
}
-// Init initializes a sqlite3 database.
-func Init(db *DB) {
+func initDB(db *DB) {
var err error
// We set the database path, first the environment variable
@@ -36,7 +35,7 @@ func Init(db *DB) {
db.Conn, err = sql.Open("sqlite3", db.Path)
if err != nil {
log.Printf("sqlite3/init.go: %s\n",
- "Failed to open database connection")
+ "failed to open database connection")
initErr(db, err)
}
@@ -50,11 +49,11 @@ func Init(db *DB) {
token TEXT NOT NULL,
genTime TEXT NOT NULL);`,
- `CREATE TABLE IF NOT EXISTS users (
+ `CREATE TABLE IF NOT EXISTS accounts (
id TEXT PRIMARY KEY,
type TEXT NOT NULL DEFAULT user,
username VARCHAR(128) NOT NULL UNIQUE,
- password TEXT NOT NULL,
+ hash TEXT NOT NULL,
regTime TEXT NOT NULL);`,
}
@@ -67,7 +66,7 @@ func Init(db *DB) {
if err != nil {
log.Printf("sqlite3/init.go: %s\n",
- "Failed to prepare statement")
+ "failed to prepare statement")
log.Println(s)
initErr(db, err)
}
@@ -76,7 +75,7 @@ func Init(db *DB) {
stmt.Close()
if err != nil {
log.Printf("sqlite3/init.go: %s\n",
- "Failed to execute statement")
+ "failed to execute statement")
log.Println(s)
initErr(db, err)
}
diff --git a/storage/sqlite3/db.go b/storage/sqlite3/db.go
deleted file mode 100644
index e949bba..0000000
--- a/storage/sqlite3/db.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package sqlite3
-
-import (
- "database/sql"
- "sync"
-)
-
-// DB holds the database connection, mutex & path.
-type DB struct {
- Path string
- Mu *sync.RWMutex
- Conn *sql.DB
-}
diff --git a/storage/storage.go b/storage/storage.go
index 24f770d..33dd29f 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -1,17 +1,23 @@
package storage
import (
+ "database/sql"
"sync"
-
- "tildegit.org/andinus/perseus/storage/sqlite3"
)
+// DB holds the database connection, mutex & path.
+type DB struct {
+ Path string
+ Mu *sync.RWMutex
+ Conn *sql.DB
+}
+
// Init initializes the database.
-func Init() *sqlite3.DB {
- var db sqlite3.DB = sqlite3.DB{
+func Init() *DB {
+ db := DB{
Mu: new(sync.RWMutex),
}
- sqlite3.Init(&db)
+ initDB(&db)
return &db
}
diff --git a/user/adduser.go b/user/adduser.go
deleted file mode 100644
index d1dbcde..0000000
--- a/user/adduser.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package user
-
-import (
- "log"
- "time"
-
- "tildegit.org/andinus/perseus/storage/sqlite3"
-)
-
-// AddUser adds the user to record.
-func (u User) AddUser(db *sqlite3.DB) error {
- // Acquire write lock on the database.
- db.Mu.Lock()
- defer db.Mu.Unlock()
-
- // Start the transaction
- tx, err := db.Conn.Begin()
- if err != nil {
- log.Printf("user/adduser.go: %s\n",
- "failed to begin transaction")
- return err
- }
-
- usrStmt, err := db.Conn.Prepare(`
-INSERT INTO users(id, username, password, regTime) values(?, ?, ?, ?)`)
- if err != nil {
- log.Printf("user/adduser.go: %s\n",
- "failed to prepare statement")
- return err
- }
- defer usrStmt.Close()
-
- _, err = usrStmt.Exec(u.ID, u.Username, u.Password, time.Now().UTC())
- if err != nil {
- log.Printf("user/adduser.go: %s\n",
- "failed to execute statement")
- return err
- }
-
- tx.Commit()
- return err
-}
diff --git a/user/getid.go b/user/getid.go
deleted file mode 100644
index 9cf8870..0000000
--- a/user/getid.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package user
-
-import (
- "log"
-
- "tildegit.org/andinus/perseus/storage/sqlite3"
-)
-
-// GetID returns id from username.
-func (u *User) GetID(db *sqlite3.DB) error {
- // Get password for this user from the database.
- stmt, err := db.Conn.Prepare("SELECT id FROM users WHERE username = ?")
- if err != nil {
- log.Printf("user/getid.go: %s\n",
- "failed to prepare statement")
- return err
- }
- defer stmt.Close()
-
- var id string
- err = stmt.QueryRow(u.Username).Scan(&id)
- if err != nil {
- log.Printf("user/getid.go: %s\n",
- "query failed")
- }
- u.ID = id
-
- return err
-}
diff --git a/web/login.html b/web/templates/login.html
similarity index 97%
rename from web/login.html
rename to web/templates/login.html
index cd0d6a7..88024e3 100644
--- a/web/login.html
+++ b/web/templates/login.html
@@ -40,7 +40,7 @@
/
Perseus
- Perseus {{ .Version }}
+ Perseus {{ if .Version}} {{ . }} {{ end }}
/
Source Code
diff --git a/web/register.html b/web/templates/register.html
similarity index 97%
rename from web/register.html
rename to web/templates/register.html
index c351ae1..998e012 100644
--- a/web/register.html
+++ b/web/templates/register.html
@@ -40,7 +40,7 @@
/
Perseus
- Perseus {{ .Version }}
+ Perseus {{ if .Version}} {{ . }} {{ end }}
/
Source Code