first commit
This commit is contained in:
97
config/certs.go
Normal file
97
config/certs.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var selfSignedTLSCertificate []byte = []byte{}
|
||||
var selfSignedTLSKey []byte = []byte{}
|
||||
|
||||
func GetTLSCertificate() []byte {
|
||||
return selfSignedTLSCertificate
|
||||
}
|
||||
|
||||
func GetTLSKey() []byte {
|
||||
return selfSignedTLSKey
|
||||
}
|
||||
|
||||
func generateSelfSignedTLSCertificate() error {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
CommonName: "ablage",
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(365 * 24 * time.Hour),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
key, err := x509.MarshalECPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: key})
|
||||
|
||||
selfSignedTLSCertificate = cert
|
||||
selfSignedTLSKey = keyPEM
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadOrGenerateTLSCertificate() error {
|
||||
if GetHttpMode() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pathTLSCertFile == "" || pathTLSKeyFile == "" {
|
||||
return generateSelfSignedTLSCertificate()
|
||||
}
|
||||
|
||||
_, err := tls.LoadX509KeyPair(pathTLSCertFile, pathTLSKeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error: Failed to load TLS certificate or key: %w", err)
|
||||
}
|
||||
|
||||
certData, err := os.ReadFile(pathTLSCertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error: Failed to read TLS certificate file: %w", err)
|
||||
}
|
||||
|
||||
keyData, err := os.ReadFile(pathTLSKeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error: Failed to read TLS key file: %w", err)
|
||||
}
|
||||
|
||||
selfSignedTLSCertificate = certData
|
||||
selfSignedTLSKey = keyData
|
||||
|
||||
return nil
|
||||
}
|
68
config/config.go
Normal file
68
config/config.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
const DefaultBasicAuthUsername string = "ablage"
|
||||
const DefaultNameDataFolder string = "data"
|
||||
const DefaultNameUploadFolder string = "upload"
|
||||
const DefaultPortToListenOn int = 13692
|
||||
const LengthOfRandomBasicAuthPassword int = 16
|
||||
const VersionString string = "1.0"
|
||||
|
||||
var randomBasicAuthPassword string = generateRandomPassword()
|
||||
|
||||
func Init() {
|
||||
err := gatherDefaultPaths()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
parseFlags()
|
||||
|
||||
if GetReadonlyMode() && GetSinkholeMode() {
|
||||
fmt.Println("Error: Cannot enable both readonly and sinkhole modes at the same time.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = loadOrGenerateTLSCertificate()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func PrintStartupBanner() {
|
||||
fmt.Println("****************************************")
|
||||
fmt.Println("* Ablage *")
|
||||
fmt.Println("****************************************")
|
||||
fmt.Printf("Version : %s\n", VersionString)
|
||||
fmt.Printf("Basic Auth mode: %v\n", GetBasicAuthMode())
|
||||
fmt.Printf("HTTP mode : %v\n", GetHttpMode())
|
||||
fmt.Printf("Readonly mode : %v\n", GetReadonlyMode())
|
||||
fmt.Printf("Sinkhole mode : %v\n", GetSinkholeMode())
|
||||
fmt.Printf("Path : %s\n", GetPathDataFolder())
|
||||
|
||||
if GetBasicAuthMode() {
|
||||
fmt.Printf("Username : %s\n", GetBasicAuthUsername())
|
||||
fmt.Printf("Password : %s\n", GetBasicAuthPassword())
|
||||
}
|
||||
|
||||
if GetHttpMode() {
|
||||
fmt.Printf("Listening on : http://0.0.0.0:%d\n", GetPortToListenOn())
|
||||
} else {
|
||||
if pathTLSCertFile == "" || pathTLSKeyFile == "" {
|
||||
fmt.Printf("TLS cert : self-signed\n")
|
||||
fmt.Printf("TLS key : self-signed\n")
|
||||
} else {
|
||||
fmt.Printf("TLS cert : %s\n", pathTLSCertFile)
|
||||
fmt.Printf("TLS key : %s\n", pathTLSKeyFile)
|
||||
}
|
||||
|
||||
fmt.Printf("Listening on : https://0.0.0.0:%d\n", GetPortToListenOn())
|
||||
}
|
||||
|
||||
fmt.Println("")
|
||||
}
|
22
config/filesystem.go
Normal file
22
config/filesystem.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var defaultPathDataFolder string = ""
|
||||
var defaultPathUploadFolder string = ""
|
||||
|
||||
func gatherDefaultPaths() error {
|
||||
execPath, err := os.Executable()
|
||||
if err != nil {
|
||||
return fmt.Errorf("[Error] Could not determine binary path: %v", err)
|
||||
}
|
||||
|
||||
defaultPathDataFolder = filepath.Join(filepath.Dir(execPath), DefaultNameDataFolder)
|
||||
defaultPathUploadFolder = filepath.Join(defaultPathDataFolder, DefaultNameUploadFolder)
|
||||
|
||||
return nil
|
||||
}
|
165
config/flags.go
Normal file
165
config/flags.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var basicAuthMode bool = false
|
||||
var basicAuthPassword string = ""
|
||||
var httpMode bool = false
|
||||
var pathDataFolder string = ""
|
||||
var pathTLSCertFile string = ""
|
||||
var pathTLSKeyFile string = ""
|
||||
var pathUploadFolder string = ""
|
||||
var portToListenOn int = DefaultPortToListenOn
|
||||
var readonlyMode bool = false
|
||||
var sinkholeMode bool = false
|
||||
|
||||
func GetBasicAuthMode() bool {
|
||||
return basicAuthMode
|
||||
}
|
||||
|
||||
func GetBasicAuthPassword() string {
|
||||
return basicAuthPassword
|
||||
}
|
||||
|
||||
func GetBasicAuthUsername() string {
|
||||
return DefaultBasicAuthUsername
|
||||
}
|
||||
|
||||
func GetHttpMode() bool {
|
||||
return httpMode
|
||||
}
|
||||
|
||||
func GetPathDataFolder() string {
|
||||
return pathDataFolder
|
||||
}
|
||||
|
||||
func GetPathTLSCertFile() string {
|
||||
return pathTLSCertFile
|
||||
}
|
||||
|
||||
func GetPathTLSKeyFile() string {
|
||||
return pathTLSKeyFile
|
||||
}
|
||||
|
||||
func GetPathUploadFolder() string {
|
||||
return pathUploadFolder
|
||||
}
|
||||
|
||||
func GetPortToListenOn() int {
|
||||
return portToListenOn
|
||||
}
|
||||
|
||||
func GetReadonlyMode() bool {
|
||||
return readonlyMode
|
||||
}
|
||||
|
||||
func GetSinkholeMode() bool {
|
||||
return sinkholeMode
|
||||
}
|
||||
|
||||
func generateRandomPassword() string {
|
||||
b := make([]byte, LengthOfRandomBasicAuthPassword)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(b)[:LengthOfRandomBasicAuthPassword]
|
||||
}
|
||||
|
||||
func parseFlags() {
|
||||
flag.BoolVar(&basicAuthMode, "auth", false, "Enable basic authentication.")
|
||||
flag.BoolVar(&httpMode, "http", false, "Enable http mode. Nothing will be encrypted.")
|
||||
flag.BoolVar(&readonlyMode, "readonly", false, "Enable readonly mode. No files can be uploaded or deleted.")
|
||||
flag.BoolVar(&sinkholeMode, "sinkhole", false, "Enable sinkhole mode. Existing files won't be visible.")
|
||||
flag.IntVar(&portToListenOn, "port", DefaultPortToListenOn, "Set Port to listen on.")
|
||||
flag.StringVar(&basicAuthPassword, "password", "", "Set password for basic authentication (or let ablage generate a random one).")
|
||||
flag.StringVar(&pathDataFolder, "path", "", "Set path to data folder (default is 'data' in the same directory as ablage).")
|
||||
flag.StringVar(&pathTLSCertFile, "cert", "", "TLS cert file")
|
||||
flag.StringVar(&pathTLSKeyFile, "key", "", "TLS key file")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
parseFlagValueBasicAuthPassword()
|
||||
parseFlagValuePortToListenOn()
|
||||
parseFlagValuePathDataFolder()
|
||||
parseFlagValuePathTLSCertFile()
|
||||
parseFlagValuePathTLSKeyFile()
|
||||
}
|
||||
|
||||
func parseFlagValueBasicAuthPassword() {
|
||||
if len(basicAuthPassword) < 1 || len(basicAuthPassword) > 128 {
|
||||
basicAuthPassword = generateRandomPassword()
|
||||
}
|
||||
}
|
||||
|
||||
func parseFlagValuePathDataFolder() {
|
||||
if pathDataFolder == "" {
|
||||
pathDataFolder = defaultPathDataFolder
|
||||
pathUploadFolder = defaultPathUploadFolder
|
||||
return
|
||||
}
|
||||
|
||||
info, err := os.Stat(pathDataFolder)
|
||||
if err != nil {
|
||||
pathDataFolder = defaultPathDataFolder
|
||||
pathUploadFolder = defaultPathUploadFolder
|
||||
return
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
pathDataFolder = defaultPathDataFolder
|
||||
pathUploadFolder = defaultPathUploadFolder
|
||||
return
|
||||
}
|
||||
|
||||
pathUploadFolder = filepath.Join(pathDataFolder, DefaultNameUploadFolder)
|
||||
}
|
||||
|
||||
func parseFlagValuePortToListenOn() {
|
||||
if portToListenOn < 1 || portToListenOn > 65535 {
|
||||
portToListenOn = DefaultPortToListenOn
|
||||
}
|
||||
}
|
||||
|
||||
func parseFlagValuePathTLSCertFile() {
|
||||
if pathTLSCertFile == "" {
|
||||
pathTLSKeyFile = ""
|
||||
return
|
||||
}
|
||||
|
||||
info, err := os.Stat(pathTLSCertFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: Failed to read cert: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
fmt.Fprintf(os.Stderr, "Error: Cert must be a file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFlagValuePathTLSKeyFile() {
|
||||
if pathTLSKeyFile == "" {
|
||||
pathTLSCertFile = ""
|
||||
return
|
||||
}
|
||||
|
||||
info, err := os.Stat(pathTLSKeyFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: Failed to read key: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
fmt.Fprintf(os.Stderr, "Error: Key must be a file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user