schastsp/server/server.go

194 lines
4.0 KiB
Go
Raw Permalink Normal View History

package server
import (
2018-09-06 14:41:03 +00:00
"errors"
"fmt"
2018-09-06 14:41:03 +00:00
"git.xdrm.io/logauth/schastsp/context"
"git.xdrm.io/logauth/schastsp/internal/scha"
"io"
"os"
"path/filepath"
)
const DEBUG = false
/* (1) Structure
---------------------------------------------------------*/
type T struct {
2018-09-06 14:41:03 +00:00
ctx *context.T // shared context
hash []byte // current key
conf string // configuration file path
}
/* (2) Constructor
*
* @ctx<context.T> Shared context
* @savePath<string> Configuration file path
*
---------------------------------------------------------*/
func New(ctx *context.T, savePath string) (*T, error) {
inst := new(T)
/* (1) Store context */
2018-09-06 14:41:03 +00:00
if ctx == nil {
return nil, errors.New("Context must not be nil")
}
inst.ctx = ctx
/* (2) Get absolute file path */
2018-09-06 14:41:03 +00:00
absolutePath, err := filepath.Abs(savePath)
if err != nil {
return nil, err
}
/* (3) Check file */
2018-09-06 14:41:03 +00:00
info, err := os.Stat(absolutePath)
if err != nil {
// Unknown error
2018-09-06 14:41:03 +00:00
if !os.IsNotExist(err) {
return nil, err
}
// File does not exist -> try to create file
2018-09-06 14:41:03 +00:00
_, err2 := os.Create(absolutePath)
if err2 != nil {
return nil, err2
}
2018-09-06 14:41:03 +00:00
// fail if exists but not regular file
} else if !info.Mode().IsRegular() {
2018-09-06 14:41:03 +00:00
return nil, errors.New("Configuration file is not a regular file")
}
/* (4) Store file path */
2018-09-06 14:41:03 +00:00
inst.conf = absolutePath
/* (5) Try to fetch hash from conf */
inst.hash = make([]byte, scha.HSIZE)
2018-09-06 14:41:03 +00:00
err = inst.fetch()
// if err != nil { return nil, err }
2018-09-06 14:41:03 +00:00
return inst, nil
}
/* (3) Handle request and send response
*
* @req<io.Reader> Request reader
* @res<io.Writer> Response Writer
*
* @return err<error> Error or NIL if not
*
---------------------------------------------------------*/
func (s *T) HandleRequest(req io.Reader, res io.Writer) error {
/* (1) Manage request
---------------------------------------------------------*/
/* (1) Read x1 */
2018-09-06 14:41:03 +00:00
x1 := make([]byte, scha.HSIZE)
read, err := req.Read(x1)
if err != nil {
return fmt.Errorf("Reading x1 : %s", err)
}
if uint16(read) != scha.HSIZE {
return fmt.Errorf("Cannot read x1 : %d / %d bytes available", read, scha.HSIZE)
}
/* (2) Read x2 */
2018-09-06 14:41:03 +00:00
x2 := make([]byte, scha.HSIZE)
read, err = req.Read(x2)
if err != nil {
return fmt.Errorf("Reading x2 : %s", err)
}
if uint16(read) != scha.HSIZE {
return fmt.Errorf("Cannot read x2 : %d / %d bytes available", read, scha.HSIZE)
}
/* (3) Manage request */
errCode, err := s.manageRequest(x1, x2)
2018-09-06 14:41:03 +00:00
if err != nil {
return err
}
/* (4) Valid authentication */
if errCode == 0 {
response := []byte{0x00}
written, err := res.Write(response)
2018-09-06 14:41:03 +00:00
if written != 1 || err != nil {
return err
}
2018-09-06 14:41:03 +00:00
return nil
}
/* (2) If not authenticated -> build resynchronisation response
---------------------------------------------------------*/
/* (1) Init y1 + y2 */
y1 := make([]byte, scha.HSIZE)
y2 := make([]byte, scha.HSIZE)
/* (2) Generate response */
err = s.generateResynchronisationResponse(y1, y2)
2018-09-06 14:41:03 +00:00
if err != nil {
return err
}
/* (3) Write error code */
responseCode := []byte{errCode}
2018-09-06 14:41:03 +00:00
written, err := res.Write(responseCode)
if err != nil {
return err
}
if written != len(responseCode) {
return errors.New("Cannot write response code")
}
/* (4) Write y1 into response */
written, err = res.Write(y1)
2018-09-06 14:41:03 +00:00
if err != nil {
return err
}
if written != len(y1) {
return errors.New("Cannot write y1")
}
/* (5) Write y2 into response */
written, err = res.Write(y2)
2018-09-06 14:41:03 +00:00
if err != nil {
return err
}
if written != len(y1) {
return errors.New("Cannot write y2")
}
return nil
}
/* (4) Apply a synchronisation key
*
* @syncKey<[]byte> Synchronisation key from client
*
* @return err<error>
*
---------------------------------------------------------*/
func (s *T) SynchronisationKey(syncKey []byte) error {
/* (1) Check size */
if uint16(len(syncKey)) != scha.HSIZE {
return fmt.Errorf("Invalid synchronisation key size (%d), expected %d bytes", len(syncKey), scha.HSIZE)
}
/* (2) Copy synchronisation key */
copy(s.hash, syncKey)
/* (3) Store new config */
s.store()
return nil
2018-09-06 14:41:03 +00:00
}