User auth added.

main
Robert 5 months ago
parent 47f5929b2d
commit 033acae279
  1. 3
      README
  2. 34
      client.go
  3. 8
      go.mod
  4. 6
      go.sum
  5. 66
      server.go

@ -1,5 +1,8 @@
```
go get github.com/mattn/go-sqlite3
go get golang.org/x/crypto/bcrypt
go mod download golang.org/x/term
go mod tidy
go run keygen.go
nano server.go

@ -7,12 +7,16 @@ import (
"fmt"
"net"
"time"
"golang.org/x/term"
"syscall"
)
type Request struct {
Username string
Password string
Operation string
Site string
Password string
VaultData string
Timestamp int64
Nonce string
}
@ -41,16 +45,28 @@ func main() {
}
defer conn.Close()
var op, site, pwd string
var username, op, site, vaultData string
fmt.Print("Username: ")
fmt.Scanln(&username)
fmt.Print("Operation (store/get): ")
fmt.Print("Password: ")
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
fmt.Println()
if err != nil {
panic(err)
}
password := string(bytePassword)
fmt.Print("Operation (register/store/get): ")
fmt.Scanln(&op)
fmt.Print("Site: ")
fmt.Scanln(&site)
if op == "store" || op == "get" {
fmt.Print("Site: ")
fmt.Scanln(&site)
}
if op == "store" {
fmt.Print("Password: ")
fmt.Scanln(&pwd)
fmt.Print("Password to store: ")
fmt.Scanln(&vaultData)
}
nonce, err := generateNonce()
@ -59,9 +75,11 @@ func main() {
}
req := Request{
Username: username,
Password: password,
Operation: op,
Site: site,
Password: pwd,
VaultData: vaultData,
Timestamp: time.Now().Unix(),
Nonce: nonce,
}

@ -2,4 +2,10 @@ module cliVault
go 1.24.3
require github.com/mattn/go-sqlite3 v1.14.28 // indirect
require (
github.com/mattn/go-sqlite3 v1.14.28
golang.org/x/crypto v0.39.0
golang.org/x/term v0.32.0
)
require golang.org/x/sys v0.33.0 // indirect

@ -1,2 +1,8 @@
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=

@ -1,6 +1,7 @@
package main
import (
"golang.org/x/crypto/bcrypt"
"crypto/aes"
"crypto/cipher"
"database/sql"
@ -13,6 +14,7 @@ import (
_ "github.com/mattn/go-sqlite3"
)
const AllowRegistration = true // Disable after users are added!
var key = []byte("2f5680a7fb57ce83e8e83dbb1114ee31") // 32 bytes
var nonceStore = struct {
@ -23,9 +25,11 @@ var nonceStore = struct {
const nonceExpiry = 30 * time.Second
type Request struct {
Username string
Password string
Operation string
Site string
Password string
VaultData string
Timestamp int64 // Unix time (seconds)
Nonce string // Random client-supplied nonce
}
@ -77,6 +81,15 @@ func isValidNonce(nonce string, timestamp int64) bool {
return true
}
func hashPassword(pw string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(pw), 12)
return string(bytes), err
}
func checkPassword(hash, pw string) error {
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw))
}
func encrypt(text string) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
@ -130,14 +143,41 @@ func handleConnection(conn net.Conn, db *sql.DB) {
return
}
if req.Operation == "register" {
if AllowRegistration == false {
enc.Encode(Response{"Registration Disabled!"})
return
}
hashed, err := hashPassword(req.Password)
if err != nil {
enc.Encode(Response{"Failed to hash password"})
return
}
_, err = db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", req.Username, hashed)
if err != nil {
enc.Encode(Response{"Registration failed (user exists?)"})
} else {
enc.Encode(Response{"Registration successful"})
}
return
}
// Authenticate all other operations
var storedHash string
err := db.QueryRow("SELECT password FROM users WHERE username = ?", req.Username).Scan(&storedHash)
if err != nil || checkPassword(storedHash, req.Password) != nil {
enc.Encode(Response{"Authentication failed"})
return
}
switch req.Operation {
case "store":
encrypted, err := encrypt(req.Password)
encrypted, err := encrypt(req.VaultData)
if err != nil {
enc.Encode(Response{"Encryption failed"})
return
}
_, err = db.Exec("INSERT OR REPLACE INTO accounts (site, password) VALUES (?, ?)", req.Site, encrypted)
_, err = db.Exec("INSERT OR REPLACE INTO accounts (user, site, password) VALUES (?, ?, ?)",
req.Username, req.Site, encrypted)
if err != nil {
enc.Encode(Response{"Database error"})
return
@ -146,7 +186,7 @@ func handleConnection(conn net.Conn, db *sql.DB) {
case "get":
var encrypted []byte
err := db.QueryRow("SELECT password FROM accounts WHERE site = ?", req.Site).Scan(&encrypted)
err := db.QueryRow("SELECT password FROM accounts WHERE user = ? AND site = ?", req.Username, req.Site).Scan(&encrypted)
if err == sql.ErrNoRows {
enc.Encode(Response{"Site not found"})
return
@ -174,10 +214,20 @@ func main() {
}
defer db.Close()
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS accounts (
site TEXT PRIMARY KEY,
password BLOB
)`)
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS users (
username TEXT PRIMARY KEY,
password TEXT
);
CREATE TABLE IF NOT EXISTS accounts (
user TEXT,
site TEXT,
password BLOB,
PRIMARY KEY(user, site),
FOREIGN KEY(user) REFERENCES users(username)
)
`)
if err != nil {
panic(err)
}

Loading…
Cancel
Save