191 lines
4.4 KiB
Go
191 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha1"
|
|
"crypto/x509"
|
|
"encoding/hex"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path"
|
|
|
|
"git.greysoh.dev/imterah/boron/bofs"
|
|
"github.com/hanwen/go-fuse/v2/fs"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
func initializeFS(cCtx *cli.Context) error {
|
|
privKeyPath := cCtx.String("key")
|
|
allowKeyGeneration := cCtx.Bool("allow-keygeneration")
|
|
|
|
srcFolder := cCtx.String("source-folder")
|
|
destFolder := cCtx.String("dest-folder")
|
|
|
|
privKeyRaw, err := os.ReadFile(privKeyPath)
|
|
|
|
var privateKey *rsa.PrivateKey
|
|
|
|
if err != nil && errors.Is(err, os.ErrNotExist) && allowKeyGeneration {
|
|
log.Println("key not found. generating key...")
|
|
privateKey, err = rsa.GenerateKey(rand.Reader, 4096)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("could not generate private key: %s", err.Error())
|
|
}
|
|
|
|
log.Println("getting key signature...")
|
|
|
|
sha1Instance := sha1.New()
|
|
keySignature := sha1Instance.Sum(nil)
|
|
|
|
if _, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, keySignature); err != nil {
|
|
return fmt.Errorf("could not get key fingerprint/signature: %s", err.Error())
|
|
}
|
|
|
|
log.Println("saving public key...")
|
|
|
|
if err := os.Mkdir(path.Join(srcFolder, "keys"), os.ModePerm); err != nil && !errors.Is(err, os.ErrExist) {
|
|
return fmt.Errorf("failed to create keys folder: %s", err.Error())
|
|
}
|
|
|
|
pubKeyFile, err := os.Create(path.Join(srcFolder, "keys", hex.EncodeToString(keySignature)+".pub"))
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open public key file: %s", err.Error())
|
|
}
|
|
|
|
// We're doing PCKS1 (todo: look into maybe changing to PCKS8?)
|
|
err = pem.Encode(
|
|
pubKeyFile,
|
|
&pem.Block{
|
|
Type: "PUBLIC KEY",
|
|
Bytes: x509.MarshalPKCS1PublicKey(&privateKey.PublicKey),
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to encode public key: %s", err.Error())
|
|
}
|
|
|
|
pubKeyFile.Close()
|
|
|
|
privKeyFile, err := os.Create(privKeyPath)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open public key file: %s", err.Error())
|
|
}
|
|
|
|
log.Println("saving private key...")
|
|
|
|
err = pem.Encode(
|
|
privKeyFile,
|
|
&pem.Block{
|
|
Type: "PRIVATE KEY",
|
|
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to encode private key: %s", err.Error())
|
|
}
|
|
|
|
privKeyFile.Close()
|
|
|
|
log.Println("finished key generation steps.")
|
|
} else if err == nil {
|
|
privKeyPem, _ := pem.Decode(privKeyRaw)
|
|
|
|
if privKeyPem.Type != "RSA PRIVATE KEY" && privKeyPem.Type != "PRIVATE KEY" {
|
|
return fmt.Errorf("decoded private key's header does not match RSA private key signature")
|
|
}
|
|
|
|
var parsedKey interface{}
|
|
|
|
if parsedKey, err = x509.ParsePKCS1PrivateKey(privKeyPem.Bytes); err != nil {
|
|
log.Println("failed to decode private key using PCKS1 format. trying PCKS8 next")
|
|
|
|
if parsedKey, err = x509.ParsePKCS8PrivateKey(privKeyPem.Bytes); err != nil {
|
|
return fmt.Errorf("failed to decode private key using PCKS8 format")
|
|
}
|
|
}
|
|
|
|
var ok bool // Hack to make Go not complain
|
|
privateKey, ok = parsedKey.(*rsa.PrivateKey)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("failed to set privateKey variable (failed typecast)")
|
|
}
|
|
} else {
|
|
return fmt.Errorf("could not read private key: %s", err.Error())
|
|
}
|
|
|
|
opts := &fs.Options{}
|
|
log.Println("mounting filesystem...")
|
|
|
|
server, err := fs.Mount(destFolder, &bofs.BoronInode{}, opts)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Println("successfully mounted filesystem.")
|
|
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt)
|
|
|
|
go func() {
|
|
for _ = range c {
|
|
log.Println("unmounting filesystem...")
|
|
err := server.Unmount()
|
|
|
|
if err != nil {
|
|
log.Println("failed to unmount filesystem.")
|
|
}
|
|
|
|
os.Exit(0)
|
|
}
|
|
}()
|
|
|
|
server.Wait()
|
|
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
app := &cli.App{
|
|
Name: "boron",
|
|
Usage: "a collaborateive end-to-end-encrypted meta-filesystem",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "key",
|
|
Usage: "armored private key to use",
|
|
Required: true,
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "allow-keygeneration",
|
|
Usage: "if true, allows keys to be generated if the keys do not exist",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "source-folder",
|
|
Usage: "source folder to use",
|
|
Required: true,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "dest-folder",
|
|
Usage: "destination folder to use",
|
|
Required: true,
|
|
},
|
|
},
|
|
Action: initializeFS,
|
|
}
|
|
|
|
if err := app.Run(os.Args); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|