package main
import (
"bytes"
"errors"
"log"
"net"
"github.com/Queueue0/qpass/internal/crypto"
"github.com/Queueue0/qpass/internal/models"
"github.com/Queueue0/qpass/internal/protocol"
"github.com/google/uuid"
)
func (app *Application) sync(p protocol.Payload, c net.Conn) {
var sd protocol.SyncData
err := sd.Decode(p.Bytes())
if err != nil {
log.Println(err.Error())
protocol.NewFail(err.Error()).WriteTo(c)
return
}
for _, p := range sd.Passwords {
exists, err := app.passwords.Exists(p.UUID.String())
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
if !exists {
err = app.passwords.DumbInsert(p)
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
continue
}
if p.Deleted {
err = app.passwords.Delete(p.UUID.String())
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
continue
}
current, err := app.passwords.GetByUUID(p.UUID.String())
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
if p.LastChanged.After(current.LastChanged) {
err = app.passwords.DumbUpdate(p)
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
}
}
id, err := uuid.Parse(sd.UUID)
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
pws, err := app.passwords.GetAllEncryptedForUser(models.User{ID: id})
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
rd := protocol.SyncData{
Passwords: pws,
}
rdBytes, err := rd.Encode()
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
response, err := protocol.NewPayload(protocol.SYNC, rdBytes)
if err != nil {
protocol.NewFail(err.Error()).WriteTo(c)
return
}
response.WriteTo(c)
}
func (app *Application) authenticate(p protocol.Payload) (bool, string, error) {
var ad protocol.AuthData
err := ad.Decode(p.Bytes())
if err != nil {
return false, "", err
}
ad.Token = crypto.ServerAuthToken(ad.Token)
u, err := app.users.ServerGetByAuthToken(ad.Token)
if err != nil {
log.Println(err.Error())
return false, "", err
}
return bytes.Equal(ad.Token, u.AuthToken), u.ID.String(), nil
}
var (
ErrUserExists = errors.New("User already exists")
ErrUserCreateFail = errors.New("Failed to create new user")
)
func (app *Application) newUser(p protocol.Payload, c net.Conn) error {
var nud protocol.NewUserData
err := nud.Decode(p.Bytes())
if err != nil {
protocol.NewFail(ErrUserCreateFail.Error()).WriteTo(c)
return err
}
nud.Token = crypto.ServerAuthToken(nud.Token)
// Check if user with same auth token or UUID exists
// if so, fail
_, err = app.users.ServerGetByAuthToken(nud.Token)
if err == nil {
protocol.NewFail(ErrUserExists.Error()).WriteTo(c)
return ErrUserExists
}
_, err = app.users.GetByUUID(nud.UUID)
if err == nil {
protocol.NewFail(ErrUserExists.Error()).WriteTo(c)
return ErrUserExists
}
if err = uuid.Validate(nud.UUID); err != nil {
temp, err := uuid.NewRandom()
if err != nil {
protocol.NewFail(ErrUserCreateFail.Error())
return err
}
nud.UUID = temp.String()
}
// Will never panic because of the above validation
UUID := uuid.MustParse(nud.UUID)
_, err = app.users.ServerInsert(models.User{ID: UUID, AuthToken: nud.Token})
if err != nil {
protocol.NewFail(ErrUserCreateFail.Error()).WriteTo(c)
return err
}
_, err = protocol.NewSuccWithData([]byte(nud.UUID)).WriteTo(c)
return err
}