Merge pull request #1 from otremblay/enter-the-share
Initial sharing work
This commit is contained in:
commit
7e34b16d77
3 changed files with 251 additions and 0 deletions
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/otremblay/sharethis
|
||||||
|
|
||||||
|
require golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941
|
||||||
2
go.sum
Normal file
2
go.sum
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941 h1:qBTHLajHecfu+xzRI9PqVDcqx7SdHj9d4B+EzSn3tAc=
|
||||||
|
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
246
main.go
Normal file
246
main.go
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
package main // import "github.com/otremblay/sharethis"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
"golang.org/x/crypto/ssh/agent"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileReq struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type chanpair struct {
|
||||||
|
sshchan *ssh.Channel
|
||||||
|
sigchan chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
bg := flag.Bool("bg", false, "sends the process in the background")
|
||||||
|
server := flag.Bool("server", false, "makes the process an http server")
|
||||||
|
flag.Parse()
|
||||||
|
if *server {
|
||||||
|
runServer("0.0.0.0", "2022", "id_rsa")
|
||||||
|
}
|
||||||
|
if len(flag.Args()) < 1 {
|
||||||
|
log.Fatalln("Need filename")
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(flag.Arg(0)); err != nil {
|
||||||
|
log.Fatalln("Can't read file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *bg {
|
||||||
|
_, err := syscall.ForkExec(os.Args[0], append([]string{os.Args[0]}, flag.Args()...), &syscall.ProcAttr{Files: []uintptr{0, 1, 2}})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("%s/.ssh/st_rsa", os.Getenv("HOME"))
|
||||||
|
auth, err := PublicKeyFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
auth = SSHAgent()
|
||||||
|
}
|
||||||
|
sshConfig := &ssh.ClientConfig{
|
||||||
|
User: "otremblay",
|
||||||
|
Auth: []ssh.AuthMethod{
|
||||||
|
auth,
|
||||||
|
},
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
connection, err := ssh.Dial("tcp", "127.0.0.1:2022", sshConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to dial: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, reqch, err := connection.OpenChannel("Nope", nil)
|
||||||
|
go ssh.DiscardRequests(reqch)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
enc := gob.NewEncoder(ch)
|
||||||
|
path = flag.Arg(0)
|
||||||
|
err = enc.Encode(&FileReq{path})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ch.Close()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
dec := gob.NewDecoder(ch)
|
||||||
|
var fr *FileReq
|
||||||
|
for {
|
||||||
|
err := dec.Decode(&fr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fr.Path == path {
|
||||||
|
defer ch.Close()
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(ch, "Sharethis error")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
io.Copy(ch, f)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PublicKeyFile(file string) (ssh.AuthMethod, error) {
|
||||||
|
buffer, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Couldn't read key file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := ssh.ParsePrivateKey(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Couldn't parse key file: %v", err)
|
||||||
|
}
|
||||||
|
return ssh.PublicKeys(key), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SSHAgent() ssh.AuthMethod {
|
||||||
|
if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
|
||||||
|
return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runServer(host, port, keyfile string) {
|
||||||
|
filemap := map[string]*ssh.Channel{}
|
||||||
|
|
||||||
|
cfg := buildCfg()
|
||||||
|
|
||||||
|
// You can generate a keypair with 'ssh-keygen -t rsa'
|
||||||
|
privateBytes, err := ioutil.ReadFile(keyfile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Sprintf("Failed to load private key (%s): %v", keyfile, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Sprintf("Failed to parse private key: %v", err))
|
||||||
|
}
|
||||||
|
cfg.AddHostKey(private)
|
||||||
|
|
||||||
|
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%s", host, port))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to listen for connection: ", err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
nConn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to accept incoming connection: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConn, chans, reqs, err := ssh.NewServerConn(nConn, cfg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to handshake: ", err)
|
||||||
|
}
|
||||||
|
// The incoming Request channel must be serviced.
|
||||||
|
go ssh.DiscardRequests(reqs)
|
||||||
|
|
||||||
|
// Service the incoming Channel channel.
|
||||||
|
go func() {
|
||||||
|
for newChannel := range chans {
|
||||||
|
channel, requests, err := newChannel.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not accept channel: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(in <-chan *ssh.Request) {
|
||||||
|
for req := range in {
|
||||||
|
req.Reply(true, nil)
|
||||||
|
}
|
||||||
|
}(requests)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
dec := gob.NewDecoder(channel)
|
||||||
|
var filereq FileReq
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := dec.Decode(&filereq)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filemap[filereq.Path] = &channel
|
||||||
|
go func() { serverConn.Wait(); delete(filemap, filereq.Path) }()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
http.ListenAndServe(":8888", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
fp := strings.TrimPrefix(req.URL.Path, "/")
|
||||||
|
if channel, ok := filemap[fp]; ok {
|
||||||
|
defer func() { (*channel).Close() }()
|
||||||
|
enc := gob.NewEncoder(*channel)
|
||||||
|
err := enc.Encode(&FileReq{fp})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(rw, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
io.Copy(rw, *channel)
|
||||||
|
delete(filemap, fp)
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
os.Exit(0)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildCfg() *ssh.ServerConfig {
|
||||||
|
authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to load authorized_keys, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizedKeysMap := map[string]bool{}
|
||||||
|
for len(authorizedKeysBytes) > 0 {
|
||||||
|
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizedKeysMap[string(pubKey.Marshal())] = true
|
||||||
|
authorizedKeysBytes = rest
|
||||||
|
}
|
||||||
|
|
||||||
|
//ssh serverstuffs
|
||||||
|
cfg := &ssh.ServerConfig{}
|
||||||
|
cfg.SetDefaults()
|
||||||
|
cfg.PasswordCallback = func(ssh.ConnMetadata, []byte) (*ssh.Permissions, error) { return nil, fmt.Errorf("Public key only") }
|
||||||
|
cfg.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
if authorizedKeysMap[string(key.Marshal())] {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unknown public key for %q", conn.User())
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue