can now store encrypted notes but you can't read them

master
Jordan Orelli 10 years ago
parent d1ef0f0597
commit 2f5dd15c77

@ -3,6 +3,7 @@ package main
import ( import (
"bufio" "bufio"
"code.google.com/p/go.crypto/ssh/terminal" "code.google.com/p/go.crypto/ssh/terminal"
"crypto/rand"
"crypto/rsa" "crypto/rsa"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -41,6 +42,7 @@ type Client struct {
prev *terminal.State prev *terminal.State
} }
// establishes a connection to the server
func (c *Client) dial() error { func (c *Client) dial() error {
addr := fmt.Sprintf("%s:%d", c.host, c.port) addr := fmt.Sprintf("%s:%d", c.host, c.port)
c.info("dialing %s", addr) c.info("dialing %s", addr)
@ -55,6 +57,7 @@ func (c *Client) dial() error {
return nil return nil
} }
// handles messages received from the current server
func (c *Client) handleMessages() { func (c *Client) handleMessages() {
messages := make(chan Envelope) messages := make(chan Envelope)
errors := make(chan error) errors := make(chan error)
@ -74,6 +77,7 @@ func (c *Client) handleMessages() {
} }
} }
// handle a message received from the server
func (c *Client) handleMessage(m Envelope) error { func (c *Client) handleMessage(m Envelope) error {
switch m.Kind { switch m.Kind {
case "meta": case "meta":
@ -83,6 +87,7 @@ func (c *Client) handleMessage(m Envelope) error {
} }
} }
// handles a meta message; that is, a message that is shown to the user
func (c *Client) handleMeta(body json.RawMessage) error { func (c *Client) handleMeta(body json.RawMessage) error {
var meta Meta var meta Meta
if err := json.Unmarshal(body, &meta); err != nil { if err := json.Unmarshal(body, &meta); err != nil {
@ -169,6 +174,7 @@ func (c *Client) control(r rune) {
c.enter() c.enter()
case 21: // ctrl+u case 21: // ctrl+u
c.clearLine() c.clearLine()
case 27: // up
case 127: // backspace case 127: // backspace
c.backspace() c.backspace()
default: default:
@ -185,16 +191,98 @@ func (c *Client) enter() {
func (c *Client) exec(line string) { func (c *Client) exec(line string) {
parts := strings.Split(line, " ") parts := strings.Split(line, " ")
if len(parts) == 0 { if len(parts) == 0 || strings.TrimSpace(parts[0]) == "" {
c.renderLine() c.renderLine()
return return
} }
switch parts[0] { switch parts[0] {
case "notes/create":
c.createNote(parts[1:])
default: default:
c.err("unrecognized client command: %s", parts[0]) c.err("unrecognized client command: %s", parts[0])
} }
} }
func (c *Client) createNote(args []string) {
if len(args) < 1 {
c.err("yeah you need to specify a title.")
return
}
title := strings.Join(args, " ")
c.info("creating new note: %s", title)
msg, err := c.readTextBlock()
if err != nil {
c.err("%v", err)
return
}
note, err := c.encryptNote(title, msg)
if err != nil {
c.err("%v", err)
return
}
if err := c.sendRequest(note); err != nil {
c.err("error sending note: %v", err)
}
}
func (c *Client) encryptNote(title string, note []rune) (NoteRequest, error) {
obj := &NoteData{
Title: title,
Body: []byte(string(note)), // lol, nooo, stahp
}
b, err := json.Marshal(obj)
if err != nil {
return nil, fmt.Errorf("unable to marshal note: %v", err)
}
ctxt, err := rsa.EncryptPKCS1v15(rand.Reader, &c.key.PublicKey, b)
if err != nil {
return nil, fmt.Errorf("unable to encrypt note: %v", err)
}
return ctxt, nil
}
func (c *Client) readTextBlock() ([]rune, error) {
// god dammit what have i gotten myself into
msg := make([]rune, 0, 400)
fmt.Print("\033[1K") // clear to beginning of current line
fmt.Print("\r") // move to beginning of current line
fmt.Print("\033[s") // save the cursor position
renderMsg := func() {
fmt.Print("\033[u") // restore cursor position
fmt.Print("\033[0J") // clear to screen end
fmt.Printf("%s", string(msg)) // write message out
}
in := bufio.NewReader(os.Stdin)
for {
r, _, err := in.ReadRune()
switch err {
case io.EOF:
return msg, nil
case nil:
default:
return nil, fmt.Errorf("error reading textblock: %v", err)
}
if unicode.IsGraphic(r) {
msg = append(msg, r)
renderMsg()
continue
}
switch r {
case 13: // enter
msg = append(msg, '\n')
renderMsg()
case 127: // backspace
if len(msg) == 0 {
break
}
msg = msg[:len(msg)-1]
renderMsg()
case 4: // ctrl+d
return msg, nil
}
}
}
func (c *Client) eof() { func (c *Client) eof() {
fmt.Print("\033[1K") // clear to beginning of current line fmt.Print("\033[1K") // clear to beginning of current line
fmt.Print("\r") // move to beginning of current line fmt.Print("\r") // move to beginning of current line

@ -0,0 +1,14 @@
package main
import ()
type NoteRequest []byte
func (n NoteRequest) Kind() string {
return "note"
}
type NoteData struct {
Title string
Body []byte
}

@ -4,8 +4,12 @@ import (
"crypto/rsa" "crypto/rsa"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
"io" "io"
"net" "net"
"strconv"
"strings"
) )
func stream(r io.Reader, c chan Envelope, e chan error, done chan interface{}) { func stream(r io.Reader, c chan Envelope, e chan error, done chan interface{}) {
@ -29,6 +33,7 @@ type serverConnection struct {
conn net.Conn conn net.Conn
nick string nick string
key rsa.PublicKey key rsa.PublicKey
db *leveldb.DB
} }
func (s *serverConnection) sendMeta(template string, args ...interface{}) { func (s *serverConnection) sendMeta(template string, args ...interface{}) {
@ -46,6 +51,8 @@ func (s *serverConnection) handleRequest(request Envelope) error {
switch request.Kind { switch request.Kind {
case "auth": case "auth":
return s.handleAuthRequest(request.Body) return s.handleAuthRequest(request.Body)
case "note":
return s.handleNoteRequest(request.Body)
default: default:
return fmt.Errorf("no such request type: %v", request.Kind) return fmt.Errorf("no such request type: %v", request.Kind)
} }
@ -59,10 +66,47 @@ func (s *serverConnection) handleAuthRequest(body json.RawMessage) error {
s.nick = auth.Nick s.nick = auth.Nick
s.key = auth.Key s.key = auth.Key
s.sendMeta("hello, %s", auth.Nick) s.sendMeta("hello, %s", auth.Nick)
if err := s.openDB(); err != nil {
error_log.Printf("failed to open database: %v", err)
}
info_log.Printf("authenticated user %s", auth.Nick) info_log.Printf("authenticated user %s", auth.Nick)
return nil return nil
} }
func (s *serverConnection) handleNoteRequest(body json.RawMessage) error {
r := &util.Range{Start: []byte("notes/")}
it := s.db.NewIterator(r, nil)
defer it.Release()
id := 0
if it.Last() {
k := it.Key()
id_s := strings.TrimPrefix(string(k), "notes/")
lastId, err := strconv.Atoi(id_s)
if err != nil {
return fmt.Errorf("error getting note id: %v", err)
}
id = lastId + 1
}
key := fmt.Sprintf("notes/%d", id)
if err := s.db.Put([]byte(key), body, nil); err != nil {
return fmt.Errorf("unable to write note to db: %v", err)
}
info_log.Printf("stored new note at %s", key)
return nil
}
func (s *serverConnection) openDB() error {
path := fmt.Sprintf("./%s.db", s.nick)
db, err := leveldb.OpenFile(path, nil)
if err != nil {
return fmt.Errorf("unable to open db file at %s: %v", path, err)
}
info_log.Printf("opened database file: %s", path)
s.db = db
return nil
}
func (s *serverConnection) run() { func (s *serverConnection) run() {
defer func() { defer func() {
s.conn.Close() s.conn.Close()

Loading…
Cancel
Save