165 lines
3.8 KiB
Go
165 lines
3.8 KiB
Go
package client
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"git.xdrm.io/schastsp/client/keyset"
|
|
"git.xdrm.io/schastsp/context"
|
|
"git.xdrm.io/schastsp/util/scha"
|
|
"io"
|
|
)
|
|
|
|
const DEBUG = false
|
|
|
|
/* (1) Structure
|
|
---------------------------------------------------------*/
|
|
type T struct {
|
|
ctx *context.T // shared context
|
|
key *keyset.T // current key
|
|
sync *keyset.T // next bufferised key
|
|
fkey *config // key file management
|
|
fsync *config // sync file management
|
|
}
|
|
|
|
/* (2) Constructor
|
|
*
|
|
* @ctx<context.T> Shared context
|
|
* @saveDir<string> Configuration path
|
|
*
|
|
---------------------------------------------------------*/
|
|
func New(ctx *context.T, saveDir string) (*T, error) {
|
|
|
|
var err error
|
|
|
|
inst := new(T)
|
|
|
|
/* (1) Store context */
|
|
if ctx == nil { return nil, errors.New("Context must not be nil"); }
|
|
inst.ctx = ctx
|
|
|
|
/* (2) Get file management for KEY */
|
|
inst.fkey, err = Config(saveDir, "key")
|
|
if err != nil { return nil, err }
|
|
|
|
/* (3) Get file management for SYNC */
|
|
inst.fsync, err = Config(saveDir, "sync")
|
|
if err != nil { return nil, err }
|
|
|
|
/* (4) Restore from config */
|
|
inst.updateConfig()
|
|
|
|
return inst, nil
|
|
|
|
}
|
|
|
|
/* (3) Processes and sends a new request
|
|
*
|
|
* @w<io.Writer> Writer to send into
|
|
*
|
|
* @return err<error> Error
|
|
*
|
|
---------------------------------------------------------*/
|
|
func (c *T) Send(w io.Writer) error {
|
|
|
|
/* (1) Generate the request */
|
|
x1 := make([]byte, scha.HSIZE)
|
|
x2 := make([]byte, scha.HSIZE)
|
|
|
|
err := c.generateRequest(x1, x2)
|
|
if err != nil { return err }
|
|
|
|
/* (2) Write request into writer */
|
|
written, err := w.Write(x1)
|
|
if err != nil { return err }
|
|
if written != len(x1) { return errors.New("Cannot write x1") }
|
|
|
|
written, err = w.Write(x2)
|
|
if err != nil { return err }
|
|
if written != len(x1) { return errors.New("Cannot write x2") }
|
|
|
|
return nil
|
|
}
|
|
|
|
/* (4) Receives and processes a response
|
|
*
|
|
* @w<io.Reader> Reader to receive from
|
|
*
|
|
* @return err<error> Error
|
|
*
|
|
---------------------------------------------------------*/
|
|
func (c *T) Receive(r io.Reader) error {
|
|
|
|
/* (1) Read error code
|
|
---------------------------------------------------------*/
|
|
errCode := make([]byte, 1)
|
|
read, err := r.Read(errCode)
|
|
if err != nil { return err }
|
|
if uint16(read) != 1 { return errors.New("Cannot read error code") }
|
|
|
|
if DEBUG { fmt.Printf("ERROR CODE : %d\n", errCode[0]) }
|
|
|
|
/* (2) Manage success
|
|
---------------------------------------------------------*/
|
|
if errCode[0] == 0 {
|
|
|
|
/* (1) If pending migration -> migrate */
|
|
if c.key.MigrationCode() == 2 {
|
|
c.migrateKey()
|
|
if DEBUG { fmt.Printf("*** VALIDATED MIGRATION\n") }
|
|
}
|
|
|
|
/* (2) No error anyway */
|
|
return nil
|
|
|
|
}
|
|
|
|
/* (3) Manage rescue
|
|
---------------------------------------------------------*/
|
|
/* (1) Read y1 */
|
|
y1 := make([]byte, scha.HSIZE)
|
|
read, err = r.Read(y1)
|
|
if err != nil { return err }
|
|
if uint16(read) != scha.HSIZE { return errors.New("Cannot read y1") }
|
|
|
|
/* (2) Read y2 */
|
|
y2 := make([]byte, scha.HSIZE)
|
|
read, err = r.Read(y2)
|
|
if err != nil { return err }
|
|
if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough y2") }
|
|
|
|
/* (3) Manage rescue mode */
|
|
err = c.rescue(y1, y2)
|
|
if err != nil { return err }
|
|
|
|
if DEBUG { fmt.Printf("*** MIGRATION PREPARED\n") }
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* (5) Returns a synchronisation key (first server connection)
|
|
*
|
|
* @return key<[]byte> Synchronisation key
|
|
* @return err<error>
|
|
*
|
|
---------------------------------------------------------*/
|
|
func (c *T) SynchronisationKey() ([]byte, error) {
|
|
|
|
/* (1) Reset keys so no value can be guessed*/
|
|
c.migrateKey(); // 1: copies 'sync' into 'key'
|
|
c.migrateKey(); // 2: copies random new 'sync' into 'key' (old 'sync)
|
|
|
|
/* (2) Get current hash */
|
|
hash, err := c.key.CurrentHash()
|
|
if err != nil { return nil, err }
|
|
|
|
/* (3) Decrement key so 'hash' is valid */
|
|
c.key.Decrement()
|
|
|
|
/* (4) Return key */
|
|
return hash, nil;
|
|
}
|