2018-04-22 19:46:31 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2018-04-24 21:10:26 +00:00
|
|
|
"fmt"
|
2018-04-25 06:29:00 +00:00
|
|
|
"git.xdrm.io/schastsp/internal/scha"
|
2018-04-22 19:46:31 +00:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"errors"
|
|
|
|
"git.xdrm.io/schastsp/context"
|
|
|
|
)
|
|
|
|
|
2018-04-22 23:08:18 +00:00
|
|
|
const DEBUG = false
|
2018-04-22 19:46:31 +00:00
|
|
|
|
|
|
|
/* (1) Structure
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
type T struct {
|
|
|
|
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 */
|
|
|
|
if ctx == nil { return nil, errors.New("Context must not be nil"); }
|
|
|
|
inst.ctx = ctx;
|
|
|
|
|
|
|
|
/* (2) Get absolute file path */
|
|
|
|
absolutePath, err := filepath.Abs(savePath);
|
|
|
|
if err != nil { return nil, err; }
|
|
|
|
|
|
|
|
/* (3) Check file */
|
|
|
|
info, err := os.Stat(absolutePath);
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
// Unknown error
|
|
|
|
if !os.IsNotExist(err) { return nil, err }
|
|
|
|
|
|
|
|
// File does not exist -> try to create file
|
|
|
|
_, err2 := os.Create(absolutePath);
|
|
|
|
if err2 != nil { return nil, err2 }
|
|
|
|
|
|
|
|
// fail if exists but not regular file
|
|
|
|
} else if !info.Mode().IsRegular() {
|
|
|
|
return nil, errors.New("Configuration file is not a regular file");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* (4) Store file path */
|
|
|
|
inst.conf = absolutePath;
|
|
|
|
|
|
|
|
/* (5) Try to fetch hash from conf */
|
2018-04-22 22:02:55 +00:00
|
|
|
inst.hash = make([]byte, scha.HSIZE)
|
2018-04-22 19:46:31 +00:00
|
|
|
err = inst.fetch();
|
2018-04-25 06:31:49 +00:00
|
|
|
// if err != nil { return nil, err }
|
2018-04-22 19:46:31 +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
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
2018-04-22 22:02:55 +00:00
|
|
|
func (s *T) HandleRequest(req io.Reader, res io.Writer) error {
|
|
|
|
|
|
|
|
/* (1) Manage request
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
/* (1) Read x1 */
|
|
|
|
x1 := make([]byte, scha.HSIZE);
|
|
|
|
read, err := req.Read(x1);
|
2018-04-24 21:42:21 +00:00
|
|
|
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) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (2) Read x2 */
|
|
|
|
x2 := make([]byte, scha.HSIZE);
|
|
|
|
read, err = req.Read(x2);
|
2018-04-24 21:42:21 +00:00
|
|
|
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) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (3) Manage request */
|
|
|
|
errCode, err := s.manageRequest(x1, x2)
|
|
|
|
if err != nil { return err }
|
|
|
|
|
|
|
|
/* (4) Valid authentication */
|
|
|
|
if errCode == 0 {
|
|
|
|
|
|
|
|
response := []byte{0x00}
|
|
|
|
written, err := res.Write(response)
|
|
|
|
if written != 1 || err != nil { return err }
|
|
|
|
|
|
|
|
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)
|
|
|
|
if err != nil { return err }
|
|
|
|
|
|
|
|
/* (3) Write error code */
|
|
|
|
responseCode := []byte{errCode}
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
if err != nil { return err }
|
|
|
|
if written != len(y1) { return errors.New("Cannot write y2") }
|
|
|
|
|
|
|
|
return nil
|
2018-04-24 21:10:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* (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-04-22 22:02:55 +00:00
|
|
|
}
|