From 1809b92e090a09106307c114130580aff4b161e4 Mon Sep 17 00:00:00 2001 From: Gisle Aune Date: Sun, 6 Jan 2019 13:12:37 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 3 +++ Gopkg.lock | 18 +++++++++++++ Gopkg.toml | 34 ++++++++++++++++++++++++ cmd/lucifer-server/main.go | 5 ++++ database/sqlite/init.go | 5 ++++ models/session.go | 23 +++++++++++++++++ models/sessions/open.go | 53 ++++++++++++++++++++++++++++++++++++++ models/user.go | 19 ++++++++++++++ models/users/login.go | 21 +++++++++++++++ models/users/register.go | 25 ++++++++++++++++++ readme.md | 10 +++++++ 11 files changed, 216 insertions(+) create mode 100644 .gitignore create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml create mode 100644 cmd/lucifer-server/main.go create mode 100644 database/sqlite/init.go create mode 100644 models/session.go create mode 100644 models/sessions/open.go create mode 100644 models/user.go create mode 100644 models/users/login.go create mode 100644 models/users/register.go create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdd594f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +lucifer-server +!cmd/**/* +vendor \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..3698146 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,18 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "bcrypt", + "blowfish" + ] + revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "a0b0b08de3e66a9e5558eaca40ab59cab7d27dbafe9eaf33270a314437c749a0" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..6ed78ba --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + branch = "master" + name = "golang.org/x/crypto" + +[prune] + go-tests = true + unused-packages = true diff --git a/cmd/lucifer-server/main.go b/cmd/lucifer-server/main.go new file mode 100644 index 0000000..7905807 --- /dev/null +++ b/cmd/lucifer-server/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} diff --git a/database/sqlite/init.go b/database/sqlite/init.go new file mode 100644 index 0000000..365a63a --- /dev/null +++ b/database/sqlite/init.go @@ -0,0 +1,5 @@ +package sqlite + +func Initialize() { + +} diff --git a/models/session.go b/models/session.go new file mode 100644 index 0000000..8b1b18f --- /dev/null +++ b/models/session.go @@ -0,0 +1,23 @@ +package models + +import ( + "time" +) + +// The Session model represents a user being logged in. +type Session struct { + ID string + UserID int + Expires time.Time +} + +// SessionRepository is an interface for all database operations +// the user model makes. +type SessionRepository interface { + // FindSessionByID finds a non-expired session by ID. + FindSessionByID(id int) (Session, error) + InsertSession(session Session) error + RemoveSession(session Session) error + ClearUserSessions(user User) error + RemoveExpiredSessions() error +} diff --git a/models/sessions/open.go b/models/sessions/open.go new file mode 100644 index 0000000..0f9cc3d --- /dev/null +++ b/models/sessions/open.go @@ -0,0 +1,53 @@ +package sessions + +import ( + "crypto/rand" + "encoding/binary" + "strconv" + "time" + + "git.aiterp.net/lucifer/lucifer/models" +) + +func Open(repo models.SessionRepository, user models.User) (models.Session, error) { + id, err := generateID() + if err != nil { + return models.Session{}, err + } + + session := models.Session{ID: id, Expires: time.Now().Add(time.Hour * 72), UserID: user.ID} + + err = repo.InsertSession(session) + if err != nil { + return models.Session{}, err + } + + return session, nil +} + +func generateID() (string, error) { + result := "S" + offset := 0 + data := make([]byte, 32) + + _, err := rand.Read(data) + if err != nil { + return "", err + } + + for len(result) < 64 { + result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36) + offset += 8 + + if offset >= 32 { + _, err = rand.Read(data) + if err != nil { + return "", err + } + + offset = 0 + } + } + + return result[:64], nil +} diff --git a/models/user.go b/models/user.go new file mode 100644 index 0000000..df7c60b --- /dev/null +++ b/models/user.go @@ -0,0 +1,19 @@ +package models + +// The User model represents a registered user. +type User struct { + ID int + Name string + PassHash []byte +} + +// UserRepository is an interface for all database operations +// the user model makes. +type UserRepository interface { + FindUserByID(id int) (User, error) + FindUserByName(name string) (User, error) + ListUsers() ([]User, error) + InsertUser(user User) (int, error) + UpdateUser(user User) error + RemoveUser(user User) error +} diff --git a/models/users/login.go b/models/users/login.go new file mode 100644 index 0000000..09c7a9b --- /dev/null +++ b/models/users/login.go @@ -0,0 +1,21 @@ +package users + +import ( + "git.aiterp.net/lucifer/lucifer/models" + "golang.org/x/crypto/bcrypt" +) + +// Login gets a user and compares the password. It does not open a session. +func Login(repo models.UserRepository, name, password string) (models.User, error) { + user, err := repo.FindUserByName(name) + if err != nil { + return models.User{}, err + } + + err = bcrypt.CompareHashAndPassword(user.PassHash, []byte(password)) + if err != nil { + return models.User{}, err + } + + return user, nil +} diff --git a/models/users/register.go b/models/users/register.go new file mode 100644 index 0000000..bec5ea8 --- /dev/null +++ b/models/users/register.go @@ -0,0 +1,25 @@ +package users + +import ( + "git.aiterp.net/lucifer/lucifer/models" + "golang.org/x/crypto/bcrypt" +) + +// Register registers a user +func Register(repo models.UserRepository, name, password string) (models.User, error) { + hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return models.User{}, err + } + + user := models.User{ID: -1, Name: name, PassHash: hash} + + id, err := repo.InsertUser(user) + if err != nil { + return models.User{}, err + } + + user.ID = id + + return user, nil +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..2aa99c2 --- /dev/null +++ b/readme.md @@ -0,0 +1,10 @@ +# Lucifer + +Lucifer is a web interface for controlling Phillips Hue bulbs and providing access control to individual users. + +## Structure +* `cmd/`: The CLI entry points. +* `models`: The models and their repository interfaces. +* `models/`: Helper functions to avoid code duplication in repository implementations. +* `database/`: Repository implementations for the various models. +* `react/`: React client. \ No newline at end of file