Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add burn operation to the client, server, and protocol #2

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Client struct {
port int
list bool
send bool
burnNum int
receiveNum int
authToken string
}
Expand Down Expand Up @@ -50,7 +51,8 @@ func (c *Client) Connect() error {
enc := gob.NewEncoder(&secureConnection)
dec := gob.NewDecoder(&secureConnection)

if c.list {
switch {
case c.list:
log.Debugf("requesting file list")

err := c.connectToServer(secure.OperationTypeList, enc, dec)
Expand All @@ -75,8 +77,7 @@ func (c *Client) Connect() error {
fmt.Printf("total: %d files\n", numFiles)
conn.Close()
log.Debugf("done listing")

} else if c.receiveNum >= 0 {
case c.receiveNum >= 0:
log.Debugf("receiving file %d", c.receiveNum)

err := c.connectToServer(secure.OperationTypeReceive, enc, dec)
Expand All @@ -98,7 +99,8 @@ func (c *Client) Connect() error {
panic(err)
}

if res.Status == secure.ReceiveDataStartResponseOK {
switch res.Status {
case secure.ReceiveDataStartResponseOK:
for {
res := secure.PacketReceiveDataNext{}
err = dec.Decode(&res)
Expand All @@ -111,14 +113,14 @@ func (c *Client) Connect() error {
}
}
log.Debugf("finished")
} else if res.Status == secure.ReceiveDataStartResponseNotFound {
case secure.ReceiveDataStartResponseNotFound:
log.Error("ngf not found")
} else {
default:
panic("unknown status")
}

conn.Close()
} else if c.send {
case c.send:
// send mode

err := c.connectToServer(secure.OperationTypeSend, enc, dec)
Expand Down Expand Up @@ -169,16 +171,45 @@ func (c *Client) Connect() error {
log.Debugf("Sent %s in %d chunks", humanize.Bytes(uint64(nBytes)), nChunks)

conn.Close()
case c.burnNum >= 0:
log.Debugf("burning file %d", c.burnNum)

err := c.connectToServer(secure.OperationTypeBurn, enc, dec)
if err != nil {
return fmt.Errorf("could not connect and auth: %v", err)
}

req := secure.PacketBurnRequest{
Id: uint32(c.burnNum),
}
err = enc.Encode(req)
if err != nil {
panic(err)
}
// expect a response telling us if we can go ahead
res := secure.PacketBurnResponse{}
err = dec.Decode(&res)
if err != nil {
panic(err)
}

switch res.Status {
case secure.BurnResponseOK:
log.Debugf("finished")
case secure.BurnResponseNotFound:
log.Error("ngf not found")
default:
panic("unknown status")
}

} else {
conn.Close()
default:
panic("no client mode set")
}
return nil

}

func (c *Client) connectToServer(op secure.OperationTypeEnum, enc *gob.Encoder, dec *gob.Decoder) error {

// list mode
startPacket := secure.PacketStartRequest{
OperationType: op,
Expand Down
64 changes: 37 additions & 27 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,39 @@ import (
"github.com/spf13/viper"
)

var CurrentVersion = "v0.0.4"
var CurrentVersion = "v0.0.5"

const ProtocolVersion = "1.1"
const ProtocolVersion = "1.2"

type PasteValue struct {
PasteRequired bool
PasteNumber uint
type ListValue struct {
Required bool
Number uint
}

func (v *PasteValue) String() string {
if v.PasteRequired {
return fmt.Sprintf("YES: %d", v.PasteNumber)
func (v *ListValue) String() string {
if v.Required {
return fmt.Sprintf("YES: %d", v.Number)
}
return "0"
}

func (v *PasteValue) Set(s string) error {
v.PasteRequired = true
func (v *ListValue) Set(s string) error {
v.Required = true
num, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return err
}

v.PasteNumber = uint(num)
v.Number = uint(num)
return nil
}

func (v *PasteValue) Type() string {
func (v *ListValue) Type() string {
return "int"

}

func getAuthTokenFromTerminal() string {
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0755)

tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0o755)
if err != nil {
log.Printf("cannot open /dev/tty to read authtoken: %v", err)
return ""
Expand All @@ -59,7 +57,9 @@ func getAuthTokenFromTerminal() string {
log.Printf("cannot set /dev/tty to raw mode: %v", err)
return ""
}
defer term.Restore(fd, oldState)
defer func() {
_ = term.Restore(fd, oldState)
}()

t := term.NewTerminal(tty, "")
pass, err := t.ReadPassword("Enter auth token: ")
Expand All @@ -76,12 +76,16 @@ func main() {

// client mode flags
isList := flag.BoolP("list", "l", false, "Returns a list of current items on the server")
isSend := flag.BoolP("copy", "c", false, "sending stdin to netgiv server (copy)")
isSend := flag.BoolP("copy", "c", false, "send stdin to netgiv server (copy)")

pasteFlag := PasteValue{}
flag.VarP(&pasteFlag, "paste", "p", "receive from netgiv server to stdout (paste), with optional number (see --list)")
pasteFlag := ListValue{}
flag.VarP(&pasteFlag, "paste", "p", "receive from netgiv server to stdout (paste), with optional id (see --list)")
flag.Lookup("paste").NoOptDefVal = "0"

burnFlag := ListValue{}
flag.VarP(&burnFlag, "burn", "b", "burn (remove/delete) the item on the netgiv server, with optional id (see --list)")
flag.Lookup("burn").NoOptDefVal = "0"

debug := flag.Bool("debug", false, "turn on debug logging")
flag.String("address", "", "IP address/hostname of the netgiv server")

Expand All @@ -93,12 +97,18 @@ func main() {

flag.Parse()

receiveNum := int(pasteFlag.PasteNumber)
if !pasteFlag.PasteRequired {
receiveNum := int(pasteFlag.Number)
if !pasteFlag.Required {
receiveNum = -1
}

viper.AddConfigPath("$HOME/.netgiv/") // call multiple times to add many search paths
burnNum := int(burnFlag.Number)
if !burnFlag.Required {
burnNum = -1
}

viper.AddConfigPath("$HOME/.netgiv/")
viper.AddConfigPath("$HOME/.config/netgiv/") // calling multiple times adds to search paths
viper.SetConfigType("yaml")

viper.SetDefault("port", 4512)
Expand All @@ -112,11 +122,10 @@ func main() {
}
}

flag.Parse()
viper.BindPFlags(flag.CommandLine)
_ = viper.BindPFlags(flag.CommandLine)

viper.SetEnvPrefix("NETGIV")
viper.BindEnv("authtoken")
_ = viper.BindEnv("authtoken")

// pull the various things into local variables
port := viper.GetInt("port") // retrieve value from viper
Expand Down Expand Up @@ -170,11 +179,12 @@ environment variable. This may be preferable in some environments.
log.Fatal("an address must be provided on the command line, or configuration")
}

log.Debugf("protocol version: %s", ProtocolVersion)
if *isServer {
s := Server{port: port, authToken: authtoken}
s.Run()
} else {
if !*isList && !*isSend && receiveNum == -1 {
if !*isList && !*isSend && burnNum == -1 && receiveNum == -1 {
// try to work out the intent based on whether or not stdin/stdout
// are ttys
stdinTTY := isatty.IsTerminal(os.Stdin.Fd())
Expand All @@ -193,7 +203,7 @@ environment variable. This may be preferable in some environments.

}

c := Client{port: port, address: address, list: *isList, send: *isSend, receiveNum: receiveNum, authToken: authtoken}
c := Client{port: port, address: address, list: *isList, send: *isSend, burnNum: burnNum, receiveNum: receiveNum, authToken: authtoken}
err := c.Connect()
if err != nil {
fmt.Print(err)
Expand Down
26 changes: 22 additions & 4 deletions secure/secure.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (s *SecureConnection) Write(p []byte) (int, error) {
var nonce [24]byte

// Create a new nonce for each message sent
rand.Read(nonce[:])
_, _ = rand.Read(nonce[:])

encryptedMessage := box.SealAfterPrecomputation(nil, p, &nonce, s.SharedKey)
sm := SecureMessage{Msg: encryptedMessage, Nonce: nonce}
Expand All @@ -145,10 +145,10 @@ func Handshake(conn *net.TCPConn) *[32]byte {

publicKey, privateKey, _ := box.GenerateKey(rand.Reader)

conn.Write(publicKey[:])
_, _ = conn.Write(publicKey[:])

peerKeyArray := make([]byte, 32)
conn.Read(peerKeyArray)
_, _ = conn.Read(peerKeyArray)
copy(peerKey[:], peerKeyArray)

box.Precompute(&sharedKey, &peerKey, privateKey)
Expand All @@ -162,10 +162,11 @@ const (
OperationTypeSend OperationTypeEnum = iota
OperationTypeList
OperationTypeReceive
OperationTypeBurn
)

// PacketStartRequest is sent from the client to the server at the beginning
// to authenticate and annonce the requested particular operation
// to authenticate and announce the requested particular operation
type PacketStartRequest struct {
OperationType OperationTypeEnum
ClientName string
Expand Down Expand Up @@ -233,3 +234,20 @@ type PacketListData struct {
Timestamp time.Time
Kind string
}

type PacketBurnRequest struct {
Id uint32
}

type PacketBurnResponse struct {
Status PacketBurnResponseEnum
}

type PacketBurnResponseEnum byte

const (
// File has been deleted
BurnResponseOK PacketBurnResponseEnum = iota
// No such file by index
BurnResponseNotFound
)
Loading