The Great Rewrite (fixes #36, #61, #94, #101)

Rewrite of the file model and pulling mechanism. Needs lots of cleanup
and bugfixes, now...
This commit is contained in:
Jakob Borg
2014-03-28 14:36:57 +01:00
parent 3700eb1e61
commit f87b1520e8
47 changed files with 2137 additions and 1902 deletions

72
cmd/stcli/logger.go Normal file
View File

@@ -0,0 +1,72 @@
package main
import (
"fmt"
"log"
"os"
)
var logger *log.Logger
func init() {
log.SetOutput(os.Stderr)
logger = log.New(os.Stderr, "", log.Flags())
}
func debugln(vals ...interface{}) {
s := fmt.Sprintln(vals...)
logger.Output(2, "DEBUG: "+s)
}
func debugf(format string, vals ...interface{}) {
s := fmt.Sprintf(format, vals...)
logger.Output(2, "DEBUG: "+s)
}
func infoln(vals ...interface{}) {
s := fmt.Sprintln(vals...)
logger.Output(2, "INFO: "+s)
}
func infof(format string, vals ...interface{}) {
s := fmt.Sprintf(format, vals...)
logger.Output(2, "INFO: "+s)
}
func okln(vals ...interface{}) {
s := fmt.Sprintln(vals...)
logger.Output(2, "OK: "+s)
}
func okf(format string, vals ...interface{}) {
s := fmt.Sprintf(format, vals...)
logger.Output(2, "OK: "+s)
}
func warnln(vals ...interface{}) {
s := fmt.Sprintln(vals...)
logger.Output(2, "WARNING: "+s)
}
func warnf(format string, vals ...interface{}) {
s := fmt.Sprintf(format, vals...)
logger.Output(2, "WARNING: "+s)
}
func fatalln(vals ...interface{}) {
s := fmt.Sprintln(vals...)
logger.Output(2, "FATAL: "+s)
os.Exit(3)
}
func fatalf(format string, vals ...interface{}) {
s := fmt.Sprintf(format, vals...)
logger.Output(2, "FATAL: "+s)
os.Exit(3)
}
func fatalErr(err error) {
if err != nil {
fatalf(err.Error())
}
}

137
cmd/stcli/main.go Normal file
View File

@@ -0,0 +1,137 @@
package main
import (
"crypto/tls"
"flag"
"io"
"log"
"os"
"path/filepath"
"github.com/calmh/syncthing/protocol"
)
var (
exit bool
cmd string
confDir string
target string
get string
pc protocol.Connection
)
func main() {
log.SetFlags(0)
log.SetOutput(os.Stdout)
flag.StringVar(&cmd, "cmd", "idx", "Command")
flag.StringVar(&confDir, "home", ".", "Certificates directory")
flag.StringVar(&target, "target", "127.0.0.1:22000", "Target node")
flag.StringVar(&get, "get", "", "Get file")
flag.BoolVar(&exit, "exit", false, "Exit after command")
flag.Parse()
connect(target)
select {}
}
func connect(target string) {
cert, err := loadCert(confDir)
if err != nil {
log.Fatal(err)
}
myID := string(certID(cert.Certificate[0]))
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
NextProtos: []string{"bep/1.0"},
ServerName: myID,
ClientAuth: tls.RequestClientCert,
SessionTicketsDisabled: true,
InsecureSkipVerify: true,
MinVersion: tls.VersionTLS12,
}
conn, err := tls.Dial("tcp", target, tlsCfg)
if err != nil {
log.Fatal(err)
}
remoteID := certID(conn.ConnectionState().PeerCertificates[0].Raw)
pc = protocol.NewConnection(remoteID, conn, conn, Model{}, nil)
select {}
}
type Model struct {
}
func prtIndex(files []protocol.FileInfo) {
for _, f := range files {
log.Printf("%q (v:%d mod:%d flags:0%o nblocks:%d)", f.Name, f.Version, f.Modified, f.Flags, len(f.Blocks))
for _, b := range f.Blocks {
log.Printf(" %6d %x", b.Size, b.Hash)
}
}
}
func (m Model) Index(nodeID string, files []protocol.FileInfo) {
log.Printf("Received index")
if cmd == "idx" {
prtIndex(files)
if get != "" {
for _, f := range files {
if f.Name == get {
go getFile(f)
break
}
}
} else if exit {
os.Exit(0)
}
}
}
func getFile(f protocol.FileInfo) {
fn := filepath.Base(f.Name)
fd, err := os.Create(fn)
if err != nil {
log.Fatal(err)
}
var offset int64
for _, b := range f.Blocks {
log.Printf("Request %q %d - %d", f.Name, offset, offset+int64(b.Size))
bs, err := pc.Request("default", f.Name, offset, int(b.Size))
log.Printf(" - got %d bytes", len(bs))
if err != nil {
log.Fatal(err)
}
offset += int64(b.Size)
fd.Write(bs)
}
fd.Close()
}
func (m Model) IndexUpdate(nodeID string, files []protocol.FileInfo) {
log.Println("Received index update")
if cmd == "idx" {
prtIndex(files)
if exit {
os.Exit(0)
}
}
}
func (m Model) Request(nodeID, repo string, name string, offset int64, size int) ([]byte, error) {
log.Println("Received request")
return nil, io.EOF
}
func (m Model) Close(nodeID string, err error) {
log.Println("Received close")
}

71
cmd/stcli/tls.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base32"
"encoding/pem"
"math/big"
"os"
"path/filepath"
"strings"
"time"
)
const (
tlsRSABits = 3072
tlsName = "syncthing"
)
func loadCert(dir string) (tls.Certificate, error) {
return tls.LoadX509KeyPair(filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem"))
}
func certID(bs []byte) string {
hf := sha256.New()
hf.Write(bs)
id := hf.Sum(nil)
return strings.Trim(base32.StdEncoding.EncodeToString(id), "=")
}
func newCertificate(dir string) {
infoln("Generating RSA certificate and key...")
priv, err := rsa.GenerateKey(rand.Reader, tlsRSABits)
fatalErr(err)
notBefore := time.Now()
notAfter := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0),
Subject: pkix.Name{
CommonName: tlsName,
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
fatalErr(err)
certOut, err := os.Create(filepath.Join(dir, "cert.pem"))
fatalErr(err)
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
okln("Created RSA certificate file")
keyOut, err := os.OpenFile(filepath.Join(dir, "key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
fatalErr(err)
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
keyOut.Close()
okln("Created RSA key file")
}