refactor
This commit is contained in:
@ -1,27 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
// TODO: depend on go-i2p/common
|
||||
|
||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
|
||||
|
||||
// I2PEncoding returns an I2P compatible base64 encoding based on a custom alphabet
|
||||
var I2PEncoding *base64.Encoding = base64.NewEncoding(alphabet)
|
||||
|
||||
// newlineDelimiter returns data for a scanner delimited by \n\n
|
||||
func NewlineDelimiter(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if i := bytes.Index(data, []byte{'\n', '\n'}); i >= 0 {
|
||||
return i + 2, data[0:i], nil
|
||||
}
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
return 0, nil, nil
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ParseZipReader(content []byte, size int) {
|
||||
zr, err := zip.NewReader(bytes.NewReader(content), int64(size))
|
||||
if err != nil {
|
||||
panic("error")
|
||||
}
|
||||
var page, attatchment int
|
||||
for _, file := range zr.File {
|
||||
fileReader, err := file.Open()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(fileReader)
|
||||
newStr := buf.String()
|
||||
if err != nil {
|
||||
log.Fatalf("Error opening enclosed zip file %s", err)
|
||||
}
|
||||
defer fileReader.Close()
|
||||
switch file.Name[:4] {
|
||||
case "atta":
|
||||
log.Printf("Attatchment num %d: %s", attatchment, newStr)
|
||||
attatchment++
|
||||
case "page":
|
||||
log.Printf("Page num %d: %s", page, newStr)
|
||||
page++
|
||||
case "avat":
|
||||
log.Printf("avatar32.png: %s", newStr)
|
||||
case "refe":
|
||||
log.Printf("references.cfg: %s", newStr)
|
||||
case "head":
|
||||
log.Printf("Headers.dat: %s", newStr)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
package enclosure
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kpetku/go-syndie/lib/common"
|
||||
"github.com/kpetku/go-syndie/lib/syndieuri"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Enclosure holds the reference to a Syndie Header and Message
|
||||
type Enclosure struct {
|
||||
Header *SyndieHeader
|
||||
Message *SyndieTrailer
|
||||
AuthenticationSig string
|
||||
AuthorizationSig string
|
||||
HmacPos int
|
||||
}
|
||||
|
||||
// OpenFile opens a file and returns a populated Enclosure
|
||||
func (enclosure *Enclosure) OpenFile(s string) *Enclosure {
|
||||
var rest2 []byte
|
||||
|
||||
file, err := os.Open(s)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(main)",
|
||||
"file": s,
|
||||
"reason": "failed to open file",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(main)",
|
||||
"file": s,
|
||||
"reason": "failed stat file",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
length := int(stat.Size())
|
||||
|
||||
log.Printf("File size is %d", length)
|
||||
buf := make([]byte, 0, length)
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Buffer(buf, length)
|
||||
scanner.Split(common.NewlineDelimiter)
|
||||
|
||||
for scanner.Scan() {
|
||||
bs := scanner.Bytes()
|
||||
if bytes.HasPrefix(bs, []byte("Syndie.Message.1.0")) {
|
||||
str := strings.SplitAfter(string(bs), "\n")
|
||||
enclosure.Header.Version = str[0]
|
||||
for _, h := range str {
|
||||
switch strings.Split(h, "=")[0] {
|
||||
case "Author":
|
||||
enclosure.Header.Author = strings.Split(h, "Author=")[1]
|
||||
case "AuthenticationMask":
|
||||
enclosure.Header.AuthenticationMask = strings.Split(h, "AuthenticationMask=")[1]
|
||||
case "TargetChannel":
|
||||
enclosure.Header.TargetChannel = strings.Split(h, "TargetChannel=")[1]
|
||||
case "PostURI":
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(strings.Split(h, "PostURI=")[1])
|
||||
enclosure.Header.PostURI = u
|
||||
case "References":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Split(h, "References=")[1:]
|
||||
for _, ref := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(ref)
|
||||
out = append(out, u)
|
||||
}
|
||||
enclosure.Header.References = out
|
||||
case "Tags":
|
||||
enclosure.Header.Tags = strings.Split(h, "Tags=")[1:]
|
||||
case "OverwriteURI":
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(strings.Split(h, "OverwriteURI=")[1])
|
||||
enclosure.Header.OverwriteURI = u
|
||||
case "ForceNewThread":
|
||||
if strings.Contains(strings.Split(h, "ForceNewThread=")[1], "true") {
|
||||
enclosure.Header.ForceNewThread = true
|
||||
}
|
||||
case "RefuseReplies":
|
||||
if strings.Contains(strings.Split(h, "RefuseReplies=")[1], "true") {
|
||||
enclosure.Header.RefuseReplies = true
|
||||
}
|
||||
case "Cancel":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Split(h, "Cancel=")[1:]
|
||||
for _, canc := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(canc)
|
||||
out = append(out, u)
|
||||
}
|
||||
enclosure.Header.Cancel = out
|
||||
case "Subject":
|
||||
enclosure.Header.Subject = strings.Split(h, "Subject=")[1]
|
||||
case "BodyKey":
|
||||
enclosure.Header.BodyKey = strings.Split(h, "BodyKey=")[1]
|
||||
case "BodyKeyPromptSalt":
|
||||
enclosure.Header.BodyKeyPromptSalt = strings.Split(h, "BodyKeyPromptSalt=")[1]
|
||||
case "BodyKeyPrompt":
|
||||
enclosure.Header.BodyKeyPrompt = strings.Split(h, "BodyKeyPrompt=")[1]
|
||||
case "Identity":
|
||||
enclosure.Header.Identity = strings.Split(h, "Identity=")[1]
|
||||
case "EncryptKey":
|
||||
enclosure.Header.EncryptKey = strings.Split(h, "EncryptKey=")[1]
|
||||
case "Name":
|
||||
enclosure.Header.Name = strings.Split(h, "Name=")[1]
|
||||
case "Description":
|
||||
enclosure.Header.Description = strings.Split(h, "Description=")[1]
|
||||
case "Edition":
|
||||
i, err := strconv.Atoi(strings.TrimRight(strings.Split(h, "=")[1], "\n"))
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(Enclosure) MarshallHeader strconv",
|
||||
"i": i,
|
||||
"reason": "conversion error",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
enclosure.Header.Edition = i
|
||||
case "PublicPosting":
|
||||
if strings.Contains(strings.Split(h, "PublicPosting=")[1], "true") {
|
||||
enclosure.Header.PublicPosting = true
|
||||
}
|
||||
case "PublicReplies":
|
||||
if strings.Contains(strings.Split(h, "PublicReplies=")[1], "true") {
|
||||
enclosure.Header.PublicReplies = true
|
||||
}
|
||||
case "AuthorizedKeys":
|
||||
enclosure.Header.AuthorizedKeys = strings.Split(h, "AuthorizedKeys=")[1:]
|
||||
case "ManagerKeys":
|
||||
enclosure.Header.ManagerKeys = strings.Split(h, "ManagerKeys=")[1:]
|
||||
case "Archives":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Split(h, "Archives=")[1:]
|
||||
for _, arch := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(arch)
|
||||
out = append(out, u)
|
||||
}
|
||||
enclosure.Header.Archives = out
|
||||
case "ChannelReadKeys":
|
||||
enclosure.Header.ChannelReadKeys = strings.Split(h, "ChannelReadKeys=")[1:]
|
||||
case "Expiration":
|
||||
enclosure.Header.Expiration = strings.Split(h, "Expiration=")[1]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if bytes.Index(bs, []byte("AuthorizationSig=")) > 0 {
|
||||
apos := bytes.Index(bs, []byte("AuthorizationSig="))
|
||||
sig := strings.Split(string(bs[apos:]), "AuthorizationSig=")
|
||||
enclosure.HmacPos = apos
|
||||
enclosure.AuthorizationSig = strings.TrimSpace(sig[1])
|
||||
}
|
||||
if bytes.Index(bs, []byte("AuthenticationSig=")) > 0 {
|
||||
apos := bytes.Index(bs, []byte("AuthenticationSig="))
|
||||
sig := strings.Split(string(bs[apos:]), "AuthenticationSig=")
|
||||
enclosure.AuthenticationSig = strings.TrimSpace(sig[1])
|
||||
}
|
||||
rest2 = append(rest2[:], bs...)
|
||||
}
|
||||
// TODO: err out here?
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(Enclosure) scanner.Scan",
|
||||
"enclosure_parsed": scanner.Bytes(),
|
||||
"reason": "invalid input scanned",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
if bytes.HasPrefix(rest2, []byte("Size=")) {
|
||||
line := strings.Split(string(rest2)[len("Size="):], "\n")
|
||||
size, err := strconv.Atoi(line[0])
|
||||
rest := strings.Join(line[1:], "\n")
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(Enclosure) MarshallTrailer",
|
||||
"size": size,
|
||||
"line": line,
|
||||
"reason": "parsing error",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
enclosure.Message.Size = size
|
||||
enclosure.Message.Raw = []byte(rest)
|
||||
} else {
|
||||
panic("Invalid trailer marshalling attempted")
|
||||
}
|
||||
return enclosure
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package enclosure
|
||||
|
||||
import (
|
||||
"github.com/kpetku/go-syndie/lib/syndieuri"
|
||||
)
|
||||
|
||||
// SyndieHeader holds a Syndie header that contains version and pairs fields:
|
||||
/*
|
||||
Author AuthenticationMask TargetChannel PostURI References Tags OverwriteURI ForceNewThread
|
||||
RefuseReplies Cancel Subject BodyKey BodyKeyPromptSalt BodyKeyPrompt Identity EncryptKey Name
|
||||
Description Edition PublicPosting PublicReplies AuthorizedKeys ManagerKeys Archives ChannelReadKeys Expiration
|
||||
*/
|
||||
type SyndieHeader struct {
|
||||
Version string
|
||||
Author string
|
||||
AuthenticationMask string
|
||||
TargetChannel string
|
||||
PostURI syndieuri.URI
|
||||
References []syndieuri.URI
|
||||
Tags []string
|
||||
OverwriteURI syndieuri.URI
|
||||
ForceNewThread bool
|
||||
RefuseReplies bool
|
||||
Cancel []syndieuri.URI
|
||||
Subject string
|
||||
BodyKey string
|
||||
BodyKeyPromptSalt string
|
||||
BodyKeyPrompt string
|
||||
Identity string
|
||||
EncryptKey string
|
||||
Name string
|
||||
Description string
|
||||
Edition int
|
||||
PublicPosting bool
|
||||
PublicReplies bool
|
||||
AuthorizedKeys []string
|
||||
ManagerKeys []string
|
||||
Archives []syndieuri.URI
|
||||
ChannelReadKeys []string
|
||||
Expiration string
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
package enclosure
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kpetku/go-syndie/lib/syndieuri"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func NewEnclosure(f *os.File, err error) (*SyndieHeader, *SyndieTrailer) {
|
||||
scanner := bufio.NewScanner(f)
|
||||
|
||||
scanner.Split(bufio.SplitFunc(doubleNewlineDelimiter))
|
||||
|
||||
success := scanner.Scan()
|
||||
encl := SyndieHeader{}
|
||||
|
||||
if validateHeader(&encl, scanner.Bytes()) != nil {
|
||||
log.Infof("Error from validateHeader! %s", err)
|
||||
}
|
||||
scanner.Scan()
|
||||
tail := SyndieTrailer{}
|
||||
if validateBody(&tail, scanner.Bytes()) != nil {
|
||||
log.Infof("Error from validateBody! %s", err)
|
||||
}
|
||||
|
||||
if serr := scanner.Err(); err != nil {
|
||||
log.Fatal(serr)
|
||||
}
|
||||
if !success {
|
||||
// False on error or EOF. Check error
|
||||
err = scanner.Err()
|
||||
if err == nil {
|
||||
log.Printf("OooF EOF")
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
return &encl, &tail
|
||||
}
|
||||
|
||||
func validateBody(e *SyndieTrailer, b []byte) error {
|
||||
if !bytes.Contains(b, []byte("Size=")) {
|
||||
return errors.New("Invalid Syndie body")
|
||||
}
|
||||
position := bytes.Index(b, []byte("\n"))
|
||||
if position > 0 {
|
||||
size, err := strconv.Atoi(string(b[5:position])) // 5 is len("Size=")
|
||||
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(Enclosure) MarshallTrailer",
|
||||
"size": size,
|
||||
"line": string(b[5:position]),
|
||||
"reason": "parsing error",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
e.Size = size
|
||||
e.Raw = b[position+1:]
|
||||
e.Body = b
|
||||
|
||||
e.AuthenticationSig = bytes.Split(b[bytes.Index(b, []byte("AuthenticationSig=")):], []byte("\n"))[0][18:]
|
||||
e.AuthorizationSig = bytes.Split(b[bytes.Index(b, []byte("AuthorizationSig=")):], []byte("\n"))[0][17:]
|
||||
} else {
|
||||
return errors.New("Flattened corrupted Syndie body...")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHeader(e *SyndieHeader, b []byte) error {
|
||||
for count, line := range bytes.SplitN(b, []byte("\n"), 2) {
|
||||
if count == 0 {
|
||||
if !bytes.Contains(line, []byte("Syndie.Message.1.0")) {
|
||||
return errors.New("Invalid Syndie message")
|
||||
}
|
||||
} else {
|
||||
err := validateHeaderLine(e, line)
|
||||
if err != nil {
|
||||
log.Fatalf("%s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHeaderLine(e *SyndieHeader, b []byte) error {
|
||||
if bytes.Contains(b, []byte("=")) {
|
||||
split := bytes.SplitN(b, []byte("="), 2)
|
||||
key := string(split[0])
|
||||
value := string(split[1])
|
||||
switch key {
|
||||
case "Author":
|
||||
e.Author = value
|
||||
case "AuthenticationMask":
|
||||
e.AuthenticationMask = value
|
||||
case "TargetChannel":
|
||||
e.TargetChannel = value
|
||||
case "PostURI":
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(value)
|
||||
e.PostURI = u
|
||||
case "References":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Fields(value)
|
||||
for _, ref := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(ref)
|
||||
out = append(out, u)
|
||||
}
|
||||
e.References = out
|
||||
case "Tags":
|
||||
e.Tags = strings.Fields(value)
|
||||
case "OverwriteURI":
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(value)
|
||||
e.OverwriteURI = u
|
||||
case "ForceNewThread":
|
||||
if strings.Contains(value, "true") {
|
||||
e.ForceNewThread = true
|
||||
}
|
||||
case "RefuseReplies":
|
||||
if strings.Contains(value, "true") {
|
||||
e.RefuseReplies = true
|
||||
}
|
||||
case "Cancel":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Fields(value)
|
||||
for _, canc := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(canc)
|
||||
out = append(out, u)
|
||||
}
|
||||
e.Cancel = out
|
||||
case "Subject":
|
||||
e.Subject = value
|
||||
case "BodyKey":
|
||||
e.BodyKey = value
|
||||
case "BodyKeyPromptSalt":
|
||||
e.BodyKeyPromptSalt = value
|
||||
case "BodyKeyPrompt":
|
||||
e.BodyKeyPrompt = value
|
||||
case "Identity":
|
||||
e.Identity = value
|
||||
case "EncryptKey":
|
||||
e.EncryptKey = value
|
||||
case "Name":
|
||||
e.Name = value
|
||||
case "Description":
|
||||
e.Description = value
|
||||
case "Edition":
|
||||
i, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(Enclosure) MarshallHeader strconv",
|
||||
"i": i,
|
||||
"reason": "conversion error",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
e.Edition = i
|
||||
case "PublicPosting":
|
||||
if strings.Contains(value, "true") {
|
||||
e.PublicPosting = true
|
||||
}
|
||||
case "PublicReplies":
|
||||
if strings.Contains(value, "true") {
|
||||
e.PublicReplies = true
|
||||
}
|
||||
case "AuthorizedKeys":
|
||||
e.AuthorizedKeys = strings.Fields(value)
|
||||
case "ManagerKeys":
|
||||
e.ManagerKeys = strings.Fields(value)
|
||||
case "Archives":
|
||||
var out []syndieuri.URI
|
||||
r := strings.Fields(value)
|
||||
for _, arch := range r {
|
||||
u := syndieuri.URI{}
|
||||
u.Marshall(arch)
|
||||
out = append(out, u)
|
||||
}
|
||||
e.Archives = out
|
||||
case "ChannelReadKeys":
|
||||
e.ChannelReadKeys = strings.Fields(value)
|
||||
case "Expiration":
|
||||
e.Expiration = value
|
||||
case "Syndie.MessageType":
|
||||
// TODO: wrong place for MessageType?
|
||||
default:
|
||||
return errors.New("corrupt header key: " + key + " value: " + value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("corrupt header")
|
||||
}
|
||||
|
||||
func doubleNewlineDelimiter(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if i := bytes.Index(data, []byte("\n\n")); i >= 0 {
|
||||
return i + 2, data[0:i], nil
|
||||
}
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
return 0, nil, nil
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
package enclosure
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/kpetku/go-syndie/lib/common"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SyndieTrailer contains a Syndie trailer that contains version and pairs fields
|
||||
type SyndieTrailer struct {
|
||||
Size int
|
||||
Raw []byte
|
||||
decrypted []byte
|
||||
AuthorizationSig []byte
|
||||
AuthenticationSig []byte
|
||||
Body []byte
|
||||
EOF int
|
||||
}
|
||||
|
||||
// SyndieTrailerPayload holds the following: rand(nonzero) padding + 0 + internalSize + totalSize + data + rand
|
||||
type SyndieTrailerPayload struct {
|
||||
InternalSize int
|
||||
TotalSize int
|
||||
|
||||
Decrypted []byte
|
||||
DecryptedRaw []byte
|
||||
IV []byte
|
||||
HMAC []byte
|
||||
BodySection []byte
|
||||
}
|
||||
|
||||
// DecryptAES decrypts a SyndieTrailer into a messagePayload
|
||||
func (trailer *SyndieTrailer) DecryptAES(key string) SyndieTrailerPayload {
|
||||
var found bool
|
||||
inner := SyndieTrailerPayload{}
|
||||
k, err := common.I2PEncoding.DecodeString(key)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(trailer) DecryptAES, DecodeString",
|
||||
"key": key,
|
||||
"reason": "unable to convert key into b64",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
block, err := aes.NewCipher([]byte(k))
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(trailer) DecryptAES, NewCipher",
|
||||
"key": key,
|
||||
"block": block,
|
||||
"reason": "invalid block AES cipher",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
inner.IV = trailer.Raw[0:16]
|
||||
inner.HMAC = trailer.Raw[trailer.Size-32 : trailer.Size]
|
||||
|
||||
decrypter := cipher.NewCBCDecrypter(block, trailer.Raw[:16])
|
||||
decrypted := make([]byte, trailer.Size+32)
|
||||
decrypter.CryptBlocks(decrypted, trailer.Raw[16:trailer.Size])
|
||||
for i := range decrypted {
|
||||
if !found && decrypted[i] == 0x0 {
|
||||
is := int(binary.BigEndian.Uint32(decrypted[i+1 : i+5]))
|
||||
ts := int(binary.BigEndian.Uint32(decrypted[i+5 : i+9]))
|
||||
if trailer.Size != ts+16 {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(trailer) DecryptAES",
|
||||
"trailer_size": trailer.Size,
|
||||
"is": is,
|
||||
"ts": ts + 16,
|
||||
"reason": "payload size did not match envelope size",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
inner.InternalSize = is
|
||||
inner.TotalSize = ts
|
||||
inner.Decrypted = decrypted[i+9 : i+9+is]
|
||||
inner.DecryptedRaw = decrypted
|
||||
|
||||
var hmacPreKey bytes.Buffer
|
||||
hmacPreKey.Write(k)
|
||||
hmacPreKey.Write(trailer.Raw[0:16])
|
||||
|
||||
sha := sha256.New()
|
||||
sha.Write(hmacPreKey.Bytes())
|
||||
|
||||
if !verifyHmac256(trailer.Raw[16:trailer.Size-32], trailer.Raw[trailer.Size-32:trailer.Size], sha.Sum(nil)) {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(trailer) DecryptAES, verifyHmac256",
|
||||
"reason": "invalid HMAC",
|
||||
}).Fatalf("%s", err)
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
return inner
|
||||
}
|
||||
|
||||
func verifyHmac256(stringToVerify []byte, signature []byte, sharedSecret []byte) bool {
|
||||
h := hmac.New(sha256.New, sharedSecret)
|
||||
h.Write(stringToVerify)
|
||||
calculated := h.Sum(nil)
|
||||
return hmac.Equal(calculated, signature)
|
||||
}
|
||||
|
||||
func colonDelimiter(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if i := bytes.Index(data, []byte{58}); i >= 0 {
|
||||
return i + 1, data[0:i], nil
|
||||
}
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
return 0, nil, nil
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
package syndieuri
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/jackpal/bencode-go"
|
||||
)
|
||||
|
||||
/*
|
||||
URI defines the URIs safely passable within syndie, capable of referencing specific resources.
|
||||
They contain one of four reference types, plus a bencoded set of attributes:
|
||||
*/
|
||||
type URI struct {
|
||||
RefType string
|
||||
Name string `bencode:",omitempty"`
|
||||
Desc string `bencode:",omitempty"`
|
||||
Tag []string `bencode:",omitempty"`
|
||||
Author string `bencode:",omitempty"`
|
||||
Net string `bencode:",omitempty"`
|
||||
ReadKeyType string `bencode:",omitempty"`
|
||||
ReadKeyData string `bencode:",omitempty"`
|
||||
PostKeyType string `bencode:",omitempty"`
|
||||
PostKeyData string `bencode:",omitempty"`
|
||||
URL string `bencode:",omitempty"`
|
||||
Channel string `bencode:",omitempty"`
|
||||
MessageID int `bencode:",omitempty"`
|
||||
Page int `bencode:",omitempty"`
|
||||
Attachment int `bencode:",omitempty"`
|
||||
Scope []string `bencode:",omitempty"`
|
||||
PostByScope []string `bencode:",omitempty"`
|
||||
Age int `bencode:",omitempty"`
|
||||
AgeLocal int `bencode:",omitempty"`
|
||||
UnreadOnly bool `bencode:",omitempty"`
|
||||
TagInclude []string `bencode:",omitempty"`
|
||||
TagRequire []string `bencode:",omitempty"`
|
||||
TagExclude []string `bencode:",omitempty"`
|
||||
TagMessages bool `bencode:",omitempty"`
|
||||
PageMin int `bencode:",omitempty"`
|
||||
PageMax int `bencode:",omitempty"`
|
||||
AttachMin int `bencode:",omitempty"`
|
||||
AttachMax int `bencode:",omitempty"`
|
||||
RefMin int `bencode:",omitempty"`
|
||||
RefMax int `bencode:",omitempty"`
|
||||
KeyMin int `bencode:",omitempty"`
|
||||
KeyMax int `bencode:",omitempty"`
|
||||
Encrypted bool `bencode:",omitempty"`
|
||||
PBE bool `bencode:",omitempty"`
|
||||
Private bool `bencode:",omitempty"`
|
||||
Public bool `bencode:",omitempty"`
|
||||
Authorized bool `bencode:",omitempty"`
|
||||
Threaded bool `bencode:",omitempty"`
|
||||
Keyword string `bencode:",omitempty"`
|
||||
Body string `bencode:",omitempty"`
|
||||
}
|
||||
|
||||
// colonDelimiter returns data for a scanner delimited by a colon
|
||||
func colonDelimiter(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
log.Printf("data was %s", data)
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if i := bytes.Index(data, []byte{58}); i >= 0 {
|
||||
return i + 1, data[0:i], nil
|
||||
}
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
// trimSyndieURI trims "urn:", "urn:syndie", and "syndie:" from the left of a string
|
||||
func trimSyndieURI(in string) string {
|
||||
if strings.HasPrefix(in, "urn:syndie:") {
|
||||
in = strings.Join(strings.Split(in, "urn:syndie:")[1:], "")
|
||||
}
|
||||
if strings.HasPrefix(in, "urn:") {
|
||||
in = strings.Join(strings.Split(in, "urn:")[1:], "")
|
||||
}
|
||||
if strings.HasPrefix(in, "syndie:") {
|
||||
in = strings.Join(strings.Split(in, "syndie:")[1:], "")
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
// prepareURI checks a string for an invalid URI and ommits the refType before bencoding the rest.
|
||||
func prepareURI(in string) (out string, err error) {
|
||||
if len(in) < 3 {
|
||||
return in, errors.New("invalid URI")
|
||||
}
|
||||
in = trimSyndieURI(in)
|
||||
switch strings.Split(strings.ToLower(in), ":")[0] {
|
||||
case "url", "channel", "search", "archive", "text":
|
||||
// Drop the RefType to prepare for bencode
|
||||
return strings.Join(strings.Split(in, ":")[1:], ":"), nil
|
||||
default:
|
||||
return in, errors.New("invalid URI refType: " + in)
|
||||
}
|
||||
}
|
||||
|
||||
// Marshall takes a URI as string and returns a populated URI
|
||||
func (u *URI) Marshall(s string) *URI {
|
||||
if len(s) < 3 {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(uri) Marshall",
|
||||
"reason": "URI was too short to process",
|
||||
}).Fatalf("URI was too short to process")
|
||||
return &URI{}
|
||||
}
|
||||
s = trimSyndieURI(s)
|
||||
u.RefType = strings.Split(s, ":")[0]
|
||||
prepared, err := prepareURI(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r := bytes.NewReader([]byte(prepared))
|
||||
|
||||
berr := bencode.Unmarshal(r, &u)
|
||||
if berr != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(uri) Marshall",
|
||||
"reason": "error while parsing bencode",
|
||||
}).Infof("%s", berr)
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
34
main.go
34
main.go
@ -1,15 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/kpetku/go-syndie/syndieutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Printf("go-syndie: startup.")
|
||||
_, err := os.Open(os.Args[1])
|
||||
var arg string
|
||||
if len(os.Args) > 0 {
|
||||
arg = os.Args[1]
|
||||
}
|
||||
|
||||
defaultKey := flag.String("key", "pjvUqwqXVD5Da7pJPVJcYStnfBrWaPqQCPN8Jw8Q-Lw=", "use specified key, default: pjvUqwqXVD5Da7pJPVJcYStnfBrWaPqQCPN8Jw8Q-Lw=")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
file, err := os.Open(arg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("Error while opening file %s", err)
|
||||
}
|
||||
|
||||
err2 := syndieutil.ParseBody(file, *defaultKey)
|
||||
|
||||
if err2 != nil {
|
||||
log.Printf("Error reading message: %s", err2.Error())
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
/*
|
||||
current, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not obtain current user")
|
||||
}
|
||||
syndieutil.FetchFromDisk(current.HomeDir + "/.syndie/archive/")
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ func ParseBody(input io.Reader, bodyKey string) error {
|
||||
|
||||
br := bufio.NewReader(input)
|
||||
var realSize int
|
||||
var e MessageHeader
|
||||
var header MessageHeader
|
||||
|
||||
line, lerr := br.ReadString('\n')
|
||||
if lerr != nil {
|
||||
return errors.New("invalid message: " + lerr.Error())
|
||||
}
|
||||
// search for the magic "Syndie.Message.1." string
|
||||
// find the magic "Syndie.Message.1." string
|
||||
if !strings.HasPrefix(line, "Syndie.Message.1.") {
|
||||
return errors.New("invalid message")
|
||||
}
|
||||
@ -52,8 +52,9 @@ func ParseBody(input io.Reader, bodyKey string) error {
|
||||
realSize = bar
|
||||
break
|
||||
}
|
||||
// do things with the header line(s), just call validateHeaderLine for now
|
||||
herr := validateHeaderLine(&e, []byte(strings.TrimSpace(line)))
|
||||
// do things with the header line(s)
|
||||
// just call validateHeaderLine for now
|
||||
herr := validateHeaderLine(&header, []byte(strings.TrimSpace(line)))
|
||||
if herr != nil {
|
||||
return errors.New("error validating header line: " + line + " error: " + herr.Error())
|
||||
}
|
||||
|
Reference in New Issue
Block a user