-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathreceive.go
122 lines (112 loc) · 3.08 KB
/
receive.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strings"
"github.com/rakoo/goax/pkg/ratchet"
"golang.org/x/crypto/openpgp/armor"
)
func receive(peer string) {
getRatchet := func(peer string) (r *ratchet.Ratchet) {
r, err := openRatchet(peer)
if err != nil {
if err == errNoRatchet {
fmt.Fprintf(os.Stderr, "No ratchet for %s, creating one.\n", peer)
r, err = createRatchet(peer)
if err != nil {
log.Fatal("Couldn't create ratchet:", err)
}
} else {
log.Fatal(err)
}
}
return r
}
stat, err := os.Stdin.Stat()
if err != nil {
log.Fatal("Couldn't stat stdin")
}
if (stat.Mode() & os.ModeCharDevice) != 0 {
// stdin is from a terminal, not from a pipe
fmt.Fprintln(os.Stderr, "Please paste in the message; when done, hit Ctrl-D\n")
}
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatal("Couldn't read from stdin: ", err)
}
blockScanner := newBlockSplitter(stdin)
var scannedSomething bool
for blockScanner.Scan() {
armorDecoder, err := armor.Decode(strings.NewReader(blockScanner.Text()))
if err != nil {
log.Fatal("Couldn't read message from stdin: ", err)
}
switch armorDecoder.Type {
case ENCRYPTED_MESSAGE_TYPE:
msg, err := ioutil.ReadAll(armorDecoder.Body)
if err != nil {
log.Fatal("Couldn't read message: ", err)
}
r := getRatchet(peer)
plaintext, err := r.Decrypt(msg)
if err != nil {
log.Fatal("Couldn't decrypt message: ", err)
}
fmt.Println("")
io.Copy(os.Stdout, bytes.NewReader(plaintext))
deleteNew(peer)
scannedSomething = true
case KEY_EXCHANGE_TYPE:
r := getRatchet(peer)
var kx ratchet.KeyExchange
json.NewDecoder(armorDecoder.Body).Decode(&kx)
err = r.CompleteKeyExchange(kx)
if err != nil && err != ratchet.ErrHandshakeComplete {
log.Fatal("Invalid key exchange material: ", err)
}
saveRatchet(r, peer)
scannedSomething = true
default:
log.Println("Unknown block type: ", armorDecoder.Type)
}
}
if err := blockScanner.Err(); err != nil {
log.Fatal("Error scanning blocks: ", err)
}
if !scannedSomething {
fmt.Fprintln(os.Stderr, "The input you provided is invalid")
os.Exit(1)
}
}
// A blockSplitter is a bufio.Scanner that splits the input into
// multiple armored blocks
type blockSplitter struct {
*bufio.Scanner
}
func newBlockSplitter(input []byte) blockSplitter {
scanner := bufio.NewScanner(bytes.NewReader(input))
split := func(data []byte, atEof bool) (advance int, token []byte, err error) {
kxType := fmt.Sprintf("-----END %s-----", KEY_EXCHANGE_TYPE)
kxTypeIdx := bytes.Index(data, []byte(kxType))
encryptedType := fmt.Sprintf("-----END %s-----", ENCRYPTED_MESSAGE_TYPE)
encryptedTypeIdx := bytes.Index(data, []byte(encryptedType))
if kxTypeIdx != -1 {
advance := kxTypeIdx + len(kxType)
return advance, data[:advance], nil
}
if encryptedTypeIdx != -1 {
advance := encryptedTypeIdx + len(encryptedType)
return advance, data[:advance], nil
}
// No end of armored block, read more
return 0, nil, nil
}
scanner.Split(split)
return blockSplitter{scanner}
}