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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/kpetku/go-syndie/syndieutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Printf("go-syndie: startup.")
|
var arg string
|
||||||
_, err := os.Open(os.Args[1])
|
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 {
|
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)
|
br := bufio.NewReader(input)
|
||||||
var realSize int
|
var realSize int
|
||||||
var e MessageHeader
|
var header MessageHeader
|
||||||
|
|
||||||
line, lerr := br.ReadString('\n')
|
line, lerr := br.ReadString('\n')
|
||||||
if lerr != nil {
|
if lerr != nil {
|
||||||
return errors.New("invalid message: " + lerr.Error())
|
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.") {
|
if !strings.HasPrefix(line, "Syndie.Message.1.") {
|
||||||
return errors.New("invalid message")
|
return errors.New("invalid message")
|
||||||
}
|
}
|
||||||
@ -52,8 +52,9 @@ func ParseBody(input io.Reader, bodyKey string) error {
|
|||||||
realSize = bar
|
realSize = bar
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// do things with the header line(s), just call validateHeaderLine for now
|
// do things with the header line(s)
|
||||||
herr := validateHeaderLine(&e, []byte(strings.TrimSpace(line)))
|
// just call validateHeaderLine for now
|
||||||
|
herr := validateHeaderLine(&header, []byte(strings.TrimSpace(line)))
|
||||||
if herr != nil {
|
if herr != nil {
|
||||||
return errors.New("error validating header line: " + line + " error: " + herr.Error())
|
return errors.New("error validating header line: " + line + " error: " + herr.Error())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user