Add basic authentication

This commit is contained in:
Torjus Håkestad 2021-12-06 06:08:17 +01:00
parent 651de90839
commit aae3d9a217
15 changed files with 1039 additions and 804 deletions

340
actions/client.go Normal file
View File

@ -0,0 +1,340 @@
package actions
import (
"bufio"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"syscall"
"time"
"gitea.benny.dog/torjus/ezshare/certs"
"gitea.benny.dog/torjus/ezshare/config"
"gitea.benny.dog/torjus/ezshare/pb"
"gitea.benny.dog/torjus/ezshare/server"
"github.com/urfave/cli/v2"
"golang.org/x/term"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func ActionClientGet(c *cli.Context) error {
addr := c.String("addr")
conn, err := grpc.DialContext(c.Context, addr, grpc.WithInsecure())
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
req := &pb.GetFileRequest{Id: arg}
resp, err := client.GetFile(c.Context, req)
if err != nil {
return err
}
filename := resp.File.FileId
if resp.File.Metadata.OriginalFilename != "" {
filename = resp.File.Metadata.OriginalFilename
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Write(resp.File.Data); err != nil {
return err
}
fmt.Printf("Wrote file '%s'\n", filename)
}
return nil
}
func ActionClientUpload(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
f, err := os.Open(arg)
if err != nil {
return err
}
data, err := io.ReadAll(f)
if err != nil {
return err
}
req := &pb.UploadFileRequest{Data: data, OriginalFilename: filepath.Base(arg)}
resp, err := client.UploadFile(c.Context, req)
if err != nil {
return err
}
fmt.Printf("%s uploaded with id %s. Available at %s\n", arg, resp.Id, resp.FileUrl)
}
return nil
}
func ActionClientList(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
resp, err := client.ListFiles(c.Context, &pb.ListFilesRequest{})
if err != nil {
return err
}
for _, elem := range resp.Files {
fmt.Println(elem.FileId)
}
return nil
}
func ActionClientDelete(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
_, err := client.DeleteFile(c.Context, &pb.DeleteFileRequest{Id: arg})
if err != nil {
return fmt.Errorf("error deleting file: %w", err)
}
fmt.Printf("Deleted file %s\n", arg)
}
return nil
}
func ActionClientLogin(c *cli.Context) error {
if err := config.CreateDefaultConfigDir(); err != nil {
return err
}
configFilePath, err := config.DefaultConfigFilePath()
if err != nil {
return err
}
if _, err := os.Stat(configFilePath); !errors.Is(err, os.ErrNotExist) {
if err == nil {
if !c.Bool("overwrite") {
return cli.Exit("Config already exists. To overwrite run with --overwrite\n", 1)
}
} else {
return err
}
}
configDirPath := filepath.Dir(configFilePath)
clientCertPath := filepath.Join(configDirPath, "client.pem")
clientKeyPath := filepath.Join(configDirPath, "client.key")
serverCertPath := filepath.Join(configDirPath, "server.pem")
if c.Args().Len() != 1 {
return cli.Exit("Need 1 argument", 1)
}
// Fetch server certificate
ctx, cancel := context.WithTimeout(c.Context, 10*time.Second)
defer cancel()
certEndpoint := fmt.Sprintf("%s/%s", c.Args().First(), "server.pem")
certReq, err := http.NewRequestWithContext(ctx, http.MethodGet, certEndpoint, nil)
if err != nil {
return cli.Exit(fmt.Sprintf("unable to create http request: %s", err), 1)
}
verbosePrint(c, fmt.Sprintf("fetching cert from %s", certEndpoint))
certResp, err := http.DefaultClient.Do(certReq)
if err != nil {
return cli.Exit(fmt.Sprintf("error fetching server cert: %s", err), 1)
}
defer certResp.Body.Close()
serverCert, err := io.ReadAll(certResp.Body)
if err != nil {
return cli.Exit(fmt.Sprintf("error reading certificate from server: %s", err), 1)
}
// Fetch metadata
mdEndpoint := fmt.Sprintf("%s/%s", c.Args().First(), "metadata")
mdReq, err := http.NewRequestWithContext(ctx, http.MethodGet, mdEndpoint, nil)
if err != nil {
return cli.Exit(fmt.Sprintf("unable to create http request: %s", err), 1)
}
verbosePrint(c, fmt.Sprintf("fetching metadata from %s", mdEndpoint))
mdResp, err := http.DefaultClient.Do(mdReq)
if err != nil {
return cli.Exit(fmt.Sprintf("error fetching server cert: %s", err), 1)
}
defer mdResp.Body.Close()
decoder := json.NewDecoder(mdResp.Body)
var md server.MetadataResponse
if err := decoder.Decode(&md); err != nil {
return cli.Exit(fmt.Sprintf("unable to decode metadata response: %s", err), 1)
}
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf("username: ")
scanner.Scan()
username := scanner.Text()
fmt.Printf("password: ")
passwordBytes, err := term.ReadPassword(int(syscall.Stdin))
if err != nil {
return cli.Exit(fmt.Sprintf("unable to read password: %s", err), 1)
}
password := string(passwordBytes)
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(serverCert) {
return cli.Exit(fmt.Sprintf("unable to use server certificate: %s", err), 1)
}
// Generate temporary self-signed cert
keyBytes, certBytes, err := certs.GenCACert()
if err != nil {
return cli.Exit(fmt.Sprintf("unable to generate self-signed certificate: %s", err), 1)
}
keyPem, err := certs.ToPEM(keyBytes, "EC PRIVATE KEY")
if err != nil {
return cli.Exit(fmt.Sprintf("unable to pem-encode key: %s", err), 1)
}
certPem, err := certs.ToPEM(certBytes, "CERTIFICATE")
if err != nil {
return cli.Exit(fmt.Sprintf("unable to pem-encode key: %s", err), 1)
}
clientCert, err := tls.X509KeyPair(certPem, keyPem)
if err != nil {
return cli.Exit(fmt.Sprintf("unable to use self-signed certificate: %s", err), 1)
}
creds := credentials.NewTLS(&tls.Config{RootCAs: certPool, Certificates: []tls.Certificate{clientCert}})
verbosePrint(c, fmt.Sprintf("dialing grpc at %s", md.GRPCEndpoint))
conn, err := grpc.DialContext(c.Context, md.GRPCEndpoint, grpc.WithTransportCredentials(creds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewUserServiceClient(conn)
resp, err := client.Login(c.Context, &pb.LoginUserRequest{Username: username, Password: password})
if err != nil {
return err
}
// Write key to file
verbosePrint(c, fmt.Sprintf("Writing client certificate key to %s", clientKeyPath))
keyFile, err := os.Create(clientKeyPath)
if err != nil {
return cli.Exit(fmt.Sprintf("unable create file for client key: %s", err), 1)
}
defer keyFile.Close()
if _, err := keyFile.Write(resp.ClientKey); err != nil {
return cli.Exit(fmt.Sprintf("unable write client key to file: %s", err), 1)
}
// Write client cert to file
verbosePrint(c, fmt.Sprintf("Writing client certificate to %s", clientKeyPath))
clientCertFile, err := os.Create(clientCertPath)
if err != nil {
return cli.Exit(fmt.Sprintf("unable create file for client cert: %s", err), 1)
}
defer clientCertFile.Close()
if _, err := clientCertFile.Write(resp.ClientCert); err != nil {
return cli.Exit(fmt.Sprintf("unable write client cert to file: %s", err), 1)
}
// Write server cer to file
verbosePrint(c, fmt.Sprintf("Writing server certificate to %s", serverCertPath))
serverCertFile, err := os.Create(serverCertPath)
if err != nil {
return cli.Exit(fmt.Sprintf("unable create file for client key: %s", err), 1)
}
defer serverCertFile.Close()
if _, err := serverCertFile.Write(serverCert); err != nil {
return cli.Exit(fmt.Sprintf("unable write client cert to file: %s", err), 1)
}
// Write config
cfg := config.FromDefault()
cfg.Client.Certs.CertificateKeyPath = clientKeyPath
cfg.Client.Certs.CertificatePath = clientCertPath
cfg.Client.DefaultServer = md.GRPCEndpoint
cfg.Client.ServerCertPath = serverCertPath
if err := cfg.ToDefaultFile(); err != nil {
return cli.Exit(fmt.Sprintf("unable write config to file: %s", err), 1)
}
return nil
}

44
actions/misc.go Normal file
View File

@ -0,0 +1,44 @@
package actions
import (
"fmt"
"gitea.benny.dog/torjus/ezshare/certs"
"gitea.benny.dog/torjus/ezshare/config"
"github.com/urfave/cli/v2"
)
func ActionGencerts(c *cli.Context) error {
outDir := "."
if c.IsSet("out-dir") {
outDir = c.String("out-dir")
}
if !c.IsSet("hostname") {
return fmt.Errorf("--hostname required")
}
hostname := c.String("hostname")
return certs.GenAllCerts(outDir, hostname)
}
func ActionInitConfig(c *cli.Context) error {
defaultCfg := config.FromDefault()
return defaultCfg.ToDefaultFile()
}
func getConfig(c *cli.Context) (*config.Config, error) {
if c.IsSet("config") {
cfgPath := c.String("config")
return config.FromFile(cfgPath)
}
cfg, err := config.FromDefaultLocations()
if err == nil {
verbosePrint(c, fmt.Sprintf("Config loaded from %s", cfg.Location()))
}
return cfg, err
}
func verbosePrint(c *cli.Context, message string) {
if c.Bool("verbose") {
fmt.Println(message)
}
}

222
actions/serve.go Normal file
View File

@ -0,0 +1,222 @@
package actions
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"time"
"gitea.benny.dog/torjus/ezshare/certs"
"gitea.benny.dog/torjus/ezshare/pb"
"gitea.benny.dog/torjus/ezshare/server"
"gitea.benny.dog/torjus/ezshare/server/interceptors"
"gitea.benny.dog/torjus/ezshare/store"
"github.com/google/uuid"
"github.com/urfave/cli/v2"
"golang.org/x/crypto/bcrypt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func ActionServe(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
// Read certificates
srvCertBytes, err := cfg.Server.GRPC.Certs.GetCertBytes()
if err != nil {
return err
}
srvKeyBytes, err := cfg.Server.GRPC.Certs.GetKeyBytes()
if err != nil {
return err
}
caCertBytes, err := cfg.Server.GRPC.CACerts.GetCertBytes()
if err != nil {
return err
}
caKeyBytes, err := cfg.Server.GRPC.CACerts.GetKeyBytes()
if err != nil {
return err
}
// Setup file store
s, fileCloseFunc, err := cfg.Server.FileStoreConfig.GetStore()
if err != nil {
return fmt.Errorf("unable to initialize file store: %w", err)
}
defer fileCloseFunc()
// Setup user store
userStore, userCloseFunc, err := cfg.Server.UserStoreConfig.GetStore()
if err != nil {
return fmt.Errorf("unable to initialize user store: %w", err)
}
defer userCloseFunc()
// Create initial admin-user if neccessary
if err := initializeUsers(userStore); err != nil {
return fmt.Errorf("error initializing store: %w", err)
}
// Setup cert store
// TODO: User proper store
certStore := store.NewMemoryStore()
// Setup cert-service
certSvc, err := certs.NewCertService(certStore, caCertBytes, caKeyBytes)
if err != nil {
return fmt.Errorf("error initializing certificate service: %w", err)
}
// Setup shutdown-handling
rootCtx, rootCancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer rootCancel()
// Used to initiate grpc shutdown
grpcCtx, grpcCancel := context.WithCancel(rootCtx)
defer grpcCancel()
// Cancelled once grpc is successfully shut down
grpcShutdownCtx, grpcShutdownCancel := context.WithCancel(context.Background())
defer grpcShutdownCancel()
// Start grpc server
go func() {
grpcAddr := cfg.Server.GRPC.ListenAddr
if c.IsSet("grpc-addr") {
grpcAddr = c.String("grpc-addr")
}
// Setup file-service
grpcFileServer := server.NewGRPCFileServiceServer(s)
grpcFileServer.Hostname = cfg.Server.Hostname
if c.IsSet("hostname") {
grpcFileServer.Hostname = c.String("hostname")
}
// Setup user-service
grpcUserServer := server.NewGRPCUserServiceServer(userStore, certSvc)
lis, err := net.Listen("tcp", grpcAddr)
if err != nil {
log.Printf("Unable to setup grpc listener: %s\n", err)
rootCancel()
}
srvCert, err := tls.X509KeyPair(srvCertBytes, srvKeyBytes)
if err != nil {
log.Printf("Unable load server certs: %s\n", err)
rootCancel()
}
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(caCertBytes) {
log.Println("Unable to load CA cert")
rootCancel()
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{srvCert},
ClientAuth: tls.RequireAnyClientCert,
ClientCAs: certPool,
}
creds := credentials.NewTLS(tlsConfig)
grpcServer := grpc.NewServer(
grpc.Creds(creds),
grpc.ChainUnaryInterceptor(interceptors.NewAuthInterceptor(&store.MemoryStore{})),
)
pb.RegisterFileServiceServer(grpcServer, grpcFileServer)
pb.RegisterUserServiceServer(grpcServer, grpcUserServer)
// wait for cancel
go func() {
<-grpcCtx.Done()
grpcServer.GracefulStop()
}()
log.Printf("Starting grpc server")
if err = grpcServer.Serve(lis); err != nil {
log.Printf("GRPC Shutdown with error: %s\n", err)
rootCancel()
}
log.Println("GRPC Shutdown")
grpcShutdownCancel()
}()
httpCtx, httpCancel := context.WithCancel(rootCtx)
defer httpCancel()
httpShutdownCtx, httpShutdownCancel := context.WithCancel(context.Background())
defer httpShutdownCancel()
// Start http server
go func() {
httpAddr := ":8088"
if c.IsSet("http-addr") {
httpAddr = c.String("http-addr")
}
httpServer := server.NewHTTPSever(s, srvCertBytes, cfg.Server.GRPCEndpoint)
httpServer.Addr = httpAddr
// wait for cancel
go func() {
<-httpCtx.Done()
timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
httpServer.Shutdown(timeoutCtx)
}()
log.Printf("Starting http server")
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("HTTP Server shutdown with error: %s\n", err)
rootCancel()
}
log.Println("HTTP Shutdown")
httpShutdownCancel()
}()
<-grpcShutdownCtx.Done()
<-httpShutdownCtx.Done()
return nil
}
func initializeUsers(us store.UserStore) error {
// TODO: Logging
userIDs, err := us.ListUsers()
if err != nil {
return err
}
if len(userIDs) != 0 {
return nil
}
// no users, create initial admin-user
log.Printf("No users in store. Creating admin-user.")
password := uuid.Must(uuid.NewRandom()).String()
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
admin := &pb.User{
Id: uuid.Must(uuid.NewRandom()).String(),
HashedPassword: hashedPassword,
Username: "admin",
UserRole: pb.User_ADMIN,
Active: true,
}
if err := us.StoreUser(admin); err != nil {
return err
}
log.Printf("user created %s:%s", admin.Username, password)
return nil
}

View File

@ -15,6 +15,19 @@ import (
"time" "time"
) )
func ToPEM(data []byte, pemType string) ([]byte, error) {
pemData := new(bytes.Buffer)
err := pem.Encode(pemData, &pem.Block{
Type: pemType,
Bytes: data,
})
if err != nil {
return nil, err
}
return pemData.Bytes(), nil
}
func WriteCert(data []byte, filename string) error { func WriteCert(data []byte, filename string) error {
// Convert to PEM // Convert to PEM
certPEM := new(bytes.Buffer) certPEM := new(bytes.Buffer)

View File

@ -1,455 +0,0 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"os/signal"
"path/filepath"
"time"
"gitea.benny.dog/torjus/ezshare/certs"
"gitea.benny.dog/torjus/ezshare/config"
"gitea.benny.dog/torjus/ezshare/pb"
"gitea.benny.dog/torjus/ezshare/server"
"gitea.benny.dog/torjus/ezshare/server/interceptors"
"gitea.benny.dog/torjus/ezshare/store"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func main() {
app := cli.App{
Name: "ezshare",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "Path to config-file.",
},
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Be more verbose",
},
},
Commands: []*cli.Command{
{
Name: "serve",
Usage: "Start ezshare server",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-grpc",
Usage: "Do not enable grpc.",
},
&cli.BoolFlag{
Name: "no-http",
Usage: "Do not enable http.",
},
&cli.StringFlag{
Name: "grpc-addr",
Usage: "Address to listen for grpc.",
},
&cli.StringFlag{
Name: "http-addr",
Usage: "Address to listen for http.",
},
&cli.StringFlag{
Name: "hostname",
Usage: "Hostname used in links",
},
},
Action: ActionServe,
},
{
Name: "client",
Usage: "Client commands",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "addr",
Usage: "Address of server.",
},
},
Subcommands: []*cli.Command{
{
Name: "get",
Usage: "Get file with id",
ArgsUsage: "ID [ID]..",
Action: ActionClientGet,
},
{
Name: "upload",
Usage: "Upload file(s)",
ArgsUsage: "PATH [PATH]..",
Action: ActionClientUpload,
},
{
Name: "delete",
Usage: "Delete file with id",
ArgsUsage: "ID [ID]..",
Action: ActionClientDelete,
},
{
Name: "list",
Usage: "List files",
Action: ActionClientList,
},
{
Name: "config-init",
Usage: "Initialize default config",
Action: ActionInitConfig,
},
},
},
{
Name: "cert",
Usage: "Certificate commands",
Subcommands: []*cli.Command{
{
Name: "gen-all",
Usage: "Generate CA, Server and Client certificates",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "out-dir",
Usage: "Directory where certificates will be stored.",
},
&cli.StringFlag{
Name: "hostname",
Usage: "Hostname used for server certificate.",
},
},
Action: ActionGencerts,
},
},
},
},
}
err := app.Run(os.Args)
if err != nil {
log.Printf("Error: %s\n", err)
}
}
func ActionServe(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
// Read certificates
srvCertBytes, err := cfg.Server.GRPC.Certs.GetCertBytes()
if err != nil {
return err
}
srvKeyBytes, err := cfg.Server.GRPC.Certs.GetKeyBytes()
if err != nil {
return err
}
caCertBytes, err := cfg.Server.GRPC.CACerts.GetCertBytes()
if err != nil {
return err
}
// Setup store
s, closeFunc, err := cfg.Server.StoreConfig.GetStore()
if err != nil {
return fmt.Errorf("unable to initialize store: %w", err)
}
defer closeFunc()
// Setup shutdown-handling
rootCtx, rootCancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer rootCancel()
// Used to initiate grpc shutdown
grpcCtx, grpcCancel := context.WithCancel(rootCtx)
defer grpcCancel()
// Cancelled once grpc is successfully shut down
grpcShutdownCtx, grpcShutdownCancel := context.WithCancel(context.Background())
defer grpcShutdownCancel()
// Start grpc server
go func() {
grpcAddr := cfg.Server.GRPC.ListenAddr
if c.IsSet("grpc-addr") {
grpcAddr = c.String("grpc-addr")
}
grpcFileServer := server.NewGRPCFileServiceServer(s)
grpcFileServer.Hostname = cfg.Server.Hostname
if c.IsSet("hostname") {
grpcFileServer.Hostname = c.String("hostname")
}
lis, err := net.Listen("tcp", grpcAddr)
if err != nil {
log.Printf("Unable to setup grpc listener: %s\n", err)
rootCancel()
}
srvCert, err := tls.X509KeyPair(srvCertBytes, srvKeyBytes)
if err != nil {
log.Printf("Unable load server certs: %s\n", err)
rootCancel()
}
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(caCertBytes) {
log.Println("Unable to load CA cert")
rootCancel()
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{srvCert},
ClientAuth: tls.RequestClientCert,
ClientCAs: certPool,
}
creds := credentials.NewTLS(tlsConfig)
grpcServer := grpc.NewServer(
grpc.Creds(creds),
grpc.ChainUnaryInterceptor(interceptors.NewAuthInterceptor(&store.MemoryStore{})),
)
pb.RegisterFileServiceServer(grpcServer, grpcFileServer)
// wait for cancel
go func() {
<-grpcCtx.Done()
grpcServer.GracefulStop()
}()
log.Printf("Starting grpc server")
if err = grpcServer.Serve(lis); err != nil {
log.Printf("GRPC Shutdown with error: %s\n", err)
rootCancel()
}
log.Println("GRPC Shutdown")
grpcShutdownCancel()
}()
httpCtx, httpCancel := context.WithCancel(rootCtx)
defer httpCancel()
httpShutdownCtx, httpShutdownCancel := context.WithCancel(context.Background())
defer httpShutdownCancel()
// Start http server
go func() {
httpAddr := ":8088"
if c.IsSet("http-addr") {
httpAddr = c.String("http-addr")
}
httpServer := server.NewHTTPSever(s)
httpServer.Addr = httpAddr
// wait for cancel
go func() {
<-httpCtx.Done()
timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
httpServer.Shutdown(timeoutCtx)
}()
log.Printf("Starting http server")
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("HTTP Server shutdown with error: %s\n", err)
rootCancel()
}
log.Println("HTTP Shutdown")
httpShutdownCancel()
}()
<-grpcShutdownCtx.Done()
<-httpShutdownCtx.Done()
return nil
}
func ActionClientGet(c *cli.Context) error {
addr := c.String("addr")
conn, err := grpc.DialContext(c.Context, addr, grpc.WithInsecure())
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
req := &pb.GetFileRequest{Id: arg}
resp, err := client.GetFile(c.Context, req)
if err != nil {
return err
}
filename := resp.File.FileId
if resp.File.Metadata.OriginalFilename != "" {
filename = resp.File.Metadata.OriginalFilename
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Write(resp.File.Data); err != nil {
return err
}
fmt.Printf("Wrote file '%s'\n", filename)
}
return nil
}
func ActionClientUpload(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
f, err := os.Open(arg)
if err != nil {
return err
}
data, err := io.ReadAll(f)
if err != nil {
return err
}
req := &pb.UploadFileRequest{Data: data, OriginalFilename: filepath.Base(arg)}
resp, err := client.UploadFile(c.Context, req)
if err != nil {
return err
}
fmt.Printf("%s uploaded with id %s. Available at %s\n", arg, resp.Id, resp.FileUrl)
}
return nil
}
func ActionClientList(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
resp, err := client.ListFiles(c.Context, &pb.ListFilesRequest{})
if err != nil {
return err
}
for _, elem := range resp.Files {
fmt.Println(elem.FileId)
}
return nil
}
func ActionClientDelete(c *cli.Context) error {
cfg, err := getConfig(c)
if err != nil {
return err
}
addr := cfg.Client.DefaultServer
if c.IsSet("addr") {
addr = c.String("addr")
}
clientCreds, err := cfg.Client.Creds()
if err != nil {
return err
}
conn, err := grpc.DialContext(c.Context, addr, grpc.WithTransportCredentials(clientCreds))
if err != nil {
return err
}
defer conn.Close()
client := pb.NewFileServiceClient(conn)
for _, arg := range c.Args().Slice() {
_, err := client.DeleteFile(c.Context, &pb.DeleteFileRequest{Id: arg})
if err != nil {
return fmt.Errorf("error deleting file: %w", err)
}
fmt.Printf("Deleted file %s\n", arg)
}
return nil
}
func ActionGencerts(c *cli.Context) error {
outDir := "."
if c.IsSet("out-dir") {
outDir = c.String("out-dir")
}
if !c.IsSet("hostname") {
return fmt.Errorf("--hostname required")
}
hostname := c.String("hostname")
return certs.GenAllCerts(outDir, hostname)
}
func ActionInitConfig(c *cli.Context) error {
defaultCfg := config.FromDefault()
return defaultCfg.ToDefaultFile()
}
func getConfig(c *cli.Context) (*config.Config, error) {
if c.IsSet("config") {
cfgPath := c.String("config")
return config.FromFile(cfgPath)
}
cfg, err := config.FromDefaultLocations()
if err == nil {
verbosePrint(c, fmt.Sprintf("Config loaded from %s", cfg.Location()))
}
return cfg, err
}
func verbosePrint(c *cli.Context, message string) {
if c.Bool("verbose") {
fmt.Println(message)
}
}

View File

@ -17,6 +17,8 @@ import (
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
) )
var ErrNotFound = fmt.Errorf("config not found")
type Config struct { type Config struct {
Server *ServerConfig `toml:"Server"` Server *ServerConfig `toml:"Server"`
Client *ClientConfig `toml:"Client"` Client *ClientConfig `toml:"Client"`
@ -30,17 +32,24 @@ type CertificatePaths struct {
type ServerConfig struct { type ServerConfig struct {
LogLevel string `toml:"LogLevel"` LogLevel string `toml:"LogLevel"`
Hostname string `toml:"Hostname"` Hostname string `toml:"Hostname"`
StoreConfig *ServerStoreConfig `toml:"Store"` GRPCEndpoint string `toml:"GRPCEndpoint"`
UserStoreConfig *ServerUserStoreConfig `toml:"UserStore"`
FileStoreConfig *ServerFileStoreConfig `toml:"FileStore"`
GRPC *ServerGRPCConfig `toml:"GRPC"` GRPC *ServerGRPCConfig `toml:"GRPC"`
HTTP *ServerHTTPConfig `toml:"HTTP"` HTTP *ServerHTTPConfig `toml:"HTTP"`
} }
type ServerStoreConfig struct { type ServerFileStoreConfig struct {
Type string `toml:"Type"` Type string `toml:"Type"`
FSStoreConfig *FSStoreConfig `toml:"Filesystem"` FSStoreConfig *FSStoreConfig `toml:"Filesystem"`
BoltStoreConfig *BoltStoreConfig `toml:"Bolt"` BoltStoreConfig *BoltStoreConfig `toml:"Bolt"`
} }
type ServerUserStoreConfig struct {
Type string `toml:"Type"`
BoltStoreConfig *BoltStoreConfig `toml:"Bolt"`
}
type BoltStoreConfig struct { type BoltStoreConfig struct {
Path string `toml:"Path"` Path string `toml:"Path"`
} }
@ -78,7 +87,9 @@ func FromDefault() *Config {
ListenAddr: ":8089", ListenAddr: ":8089",
}, },
}, },
Client: &ClientConfig{}, Client: &ClientConfig{
Certs: &CertificatePaths{},
},
} }
return cfg return cfg
@ -97,6 +108,9 @@ func FromReader(r io.Reader) (*Config, error) {
func FromFile(path string) (*Config, error) { func FromFile(path string) (*Config, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("unable to open config-file: %w", err) return nil, fmt.Errorf("unable to open config-file: %w", err)
} }
defer f.Close() defer f.Close()
@ -188,7 +202,7 @@ func (cc *ClientConfig) Creds() (credentials.TransportCredentials, error) {
return credentials.NewTLS(config), nil return credentials.NewTLS(config), nil
} }
func (c *Config) ToDefaultFile() error { func CreateDefaultConfigDir() error {
userConfigDir, err := os.UserConfigDir() userConfigDir, err := os.UserConfigDir()
if err != nil { if err != nil {
return err return err
@ -207,8 +221,25 @@ func (c *Config) ToDefaultFile() error {
return fmt.Errorf("config-directory is not a directory") return fmt.Errorf("config-directory is not a directory")
} }
} }
return nil
}
func DefaultConfigFilePath() (string, error) {
userConfigDir, err := os.UserConfigDir()
if err != nil {
return "", err
}
return filepath.Join(userConfigDir, "ezshare", "ezshare.toml"), nil
configFilePath := filepath.Join(configDirPath, "ezshare.toml") }
func (c *Config) ToDefaultFile() error {
if err := CreateDefaultConfigDir(); err != nil {
return err
}
configFilePath, err := DefaultConfigFilePath()
if err != nil {
return err
}
_, err = os.Stat(configFilePath) _, err = os.Stat(configFilePath)
if err != nil { if err != nil {
if !errors.Is(err, fs.ErrNotExist) { if !errors.Is(err, fs.ErrNotExist) {
@ -226,7 +257,7 @@ func (c *Config) ToDefaultFile() error {
return fmt.Errorf("config-file already exists") return fmt.Errorf("config-file already exists")
} }
func (sc *ServerStoreConfig) GetStore() (store.FileStore, func() error, error) { func (sc *ServerFileStoreConfig) GetStore() (store.FileStore, func() error, error) {
nopCloseFunc := func() error { return nil } nopCloseFunc := func() error { return nil }
if strings.EqualFold(sc.Type, "bolt") { if strings.EqualFold(sc.Type, "bolt") {
s, err := store.NewBoltStore(sc.BoltStoreConfig.Path) s, err := store.NewBoltStore(sc.BoltStoreConfig.Path)
@ -243,6 +274,39 @@ func (sc *ServerStoreConfig) GetStore() (store.FileStore, func() error, error) {
if strings.EqualFold(sc.Type, "memory") { if strings.EqualFold(sc.Type, "memory") {
return store.NewMemoryStore(), nopCloseFunc, nil return store.NewMemoryStore(), nopCloseFunc, nil
} }
if strings.EqualFold(sc.Type, "bolt") {
s, err := store.NewBoltStore(sc.BoltStoreConfig.Path)
if err != nil {
return nil, nil, err
}
closeFunc := func() error { return s.Close() }
return s, closeFunc, nil
}
return nil, nil, fmt.Errorf("invalid store config")
}
func (sc *ServerUserStoreConfig) GetStore() (store.UserStore, func() error, error) {
nopCloseFunc := func() error { return nil }
if strings.EqualFold(sc.Type, "bolt") {
s, err := store.NewBoltStore(sc.BoltStoreConfig.Path)
if err != nil {
return nil, nil, err
}
return s, s.Close, err
}
if strings.EqualFold(sc.Type, "memory") {
return store.NewMemoryStore(), nopCloseFunc, nil
}
if strings.EqualFold(sc.Type, "bolt") {
s, err := store.NewBoltStore(sc.BoltStoreConfig.Path)
if err != nil {
return nil, nil, err
}
closeFunc := func() error { return s.Close() }
return s, closeFunc, nil
}
return nil, nil, fmt.Errorf("invalid store config") return nil, nil, fmt.Errorf("invalid store config")
} }

View File

@ -12,23 +12,38 @@ LogLevel = "INFO"
# Required # Required
Hostname = "localhost" Hostname = "localhost"
# Storage configuration # Endpoint reachable by clients
[Server.Store] # Fetched by clients for automatic setup
# Required
GRPCEndpoint = "localhost:50051"
# File store configuration
[Server.FileStore]
# How server stores file # How server stores file
# Must be one of: filesystem, memory, bolt # Must be one of: filesystem, memory, bolt
# Required # Required
Type = "filesystem" Type = "bolt"
[Server.Store.Bolt] [Server.FileStore.Bolt]
# Where the bolt-db is stored # Where the bolt-db is stored
# Required if store-type is bolt # Required if store-type is bolt
Path = "" Path = "/data/files.db"
[Server.Store.Filesystem] [Server.FileStore.Filesystem]
# Where files are stored # Where files are stored
# Required if store-type is filesystem # Required if store-type is filesystem
Dir = "/data" Dir = "/data"
[Server.UserStore]
# What store to use for users
# Must be one of: memory, bolt
# Required
Type = "bolt"
[Server.UserStore.Bolt]
# Path to bolt database-file
Path = "/data/users.db"
# GRPC Configuration # GRPC Configuration
[Server.GRPC] [Server.GRPC]
# Address to listen to # Address to listen to

3
go.mod
View File

@ -10,6 +10,7 @@ require (
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
go.etcd.io/bbolt v1.3.6 go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
google.golang.org/grpc v1.42.0 google.golang.org/grpc v1.42.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
) )
@ -19,7 +20,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/net v0.0.0-20211203184738-4852103109b8 // indirect golang.org/x/net v0.0.0-20211203184738-4852103109b8 // indirect
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9 // indirect google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9 // indirect

6
go.sum
View File

@ -109,9 +109,11 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

142
main.go Normal file
View File

@ -0,0 +1,142 @@
package main
import (
"log"
"os"
"gitea.benny.dog/torjus/ezshare/actions"
"github.com/urfave/cli/v2"
)
const Version = "v0.1.1"
func main() {
cli.VersionFlag = &cli.BoolFlag{Name: "version"}
app := cli.App{
Name: "ezshare",
Version: Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "Path to config-file.",
},
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Be more verbose",
},
},
Commands: []*cli.Command{
{
Name: "serve",
Usage: "Start ezshare server",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "no-grpc",
Usage: "Do not enable grpc.",
},
&cli.BoolFlag{
Name: "no-http",
Usage: "Do not enable http.",
},
&cli.StringFlag{
Name: "grpc-addr",
Usage: "Address to listen for grpc.",
},
&cli.StringFlag{
Name: "http-addr",
Usage: "Address to listen for http.",
},
&cli.StringFlag{
Name: "hostname",
Usage: "Hostname used in links",
},
},
Action: actions.ActionServe,
},
{
Name: "client",
Usage: "Client commands",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "addr",
Usage: "Address of server.",
},
},
Subcommands: []*cli.Command{
{
Name: "get",
Usage: "Get file with id",
ArgsUsage: "ID [ID]..",
Action: actions.ActionClientGet,
},
{
Name: "upload",
Usage: "Upload file(s)",
ArgsUsage: "PATH [PATH]..",
Action: actions.ActionClientUpload,
},
{
Name: "delete",
Usage: "Delete file with id",
ArgsUsage: "ID [ID]..",
Action: actions.ActionClientDelete,
},
{
Name: "list",
Usage: "List files",
Action: actions.ActionClientList,
},
{
Name: "login",
Usage: "Login and retrieve client cert",
ArgsUsage: "[PROTO://]HOSTNAME[:PORT]",
Action: actions.ActionClientLogin,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
Usage: "Username used for login.",
},
&cli.BoolFlag{
Name: "overwrite",
Usage: "Overwrite existing config",
},
},
},
{
Name: "config-init",
Usage: "Initialize default config",
Action: actions.ActionInitConfig,
},
},
},
{
Name: "cert",
Usage: "Certificate commands",
Subcommands: []*cli.Command{
{
Name: "gen-all",
Usage: "Generate CA, Server and Client certificates",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "out-dir",
Usage: "Directory where certificates will be stored.",
},
&cli.StringFlag{
Name: "hostname",
Usage: "Hostname used for server certificate.",
},
},
Action: actions.ActionGencerts,
},
},
},
},
}
err := app.Run(os.Args)
if err != nil {
log.Printf("Error: %s\n", err)
}
}

View File

@ -769,10 +769,8 @@ type LoginUserRequest struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Types that are assignable to RequestedLogin: Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
// *LoginUserRequest_WithToken Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
// *LoginUserRequest_WithPassword
RequestedLogin isLoginUserRequest_RequestedLogin `protobuf_oneof:"requested_login"`
} }
func (x *LoginUserRequest) Reset() { func (x *LoginUserRequest) Reset() {
@ -807,51 +805,27 @@ func (*LoginUserRequest) Descriptor() ([]byte, []int) {
return file_protos_ezshare_proto_rawDescGZIP(), []int{13} return file_protos_ezshare_proto_rawDescGZIP(), []int{13}
} }
func (m *LoginUserRequest) GetRequestedLogin() isLoginUserRequest_RequestedLogin { func (x *LoginUserRequest) GetUsername() string {
if m != nil { if x != nil {
return m.RequestedLogin return x.Username
} }
return nil return ""
} }
func (x *LoginUserRequest) GetWithToken() *LoginUserRequest_TokenLogin { func (x *LoginUserRequest) GetPassword() string {
if x, ok := x.GetRequestedLogin().(*LoginUserRequest_WithToken); ok { if x != nil {
return x.WithToken return x.Password
} }
return nil return ""
} }
func (x *LoginUserRequest) GetWithPassword() *LoginUserRequest_UserPasswordLogin {
if x, ok := x.GetRequestedLogin().(*LoginUserRequest_WithPassword); ok {
return x.WithPassword
}
return nil
}
type isLoginUserRequest_RequestedLogin interface {
isLoginUserRequest_RequestedLogin()
}
type LoginUserRequest_WithToken struct {
WithToken *LoginUserRequest_TokenLogin `protobuf:"bytes,1,opt,name=with_token,json=withToken,proto3,oneof"`
}
type LoginUserRequest_WithPassword struct {
WithPassword *LoginUserRequest_UserPasswordLogin `protobuf:"bytes,2,opt,name=with_password,json=withPassword,proto3,oneof"`
}
func (*LoginUserRequest_WithToken) isLoginUserRequest_RequestedLogin() {}
func (*LoginUserRequest_WithPassword) isLoginUserRequest_RequestedLogin() {}
type LoginUserResponse struct { type LoginUserResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
ServerCert []byte `protobuf:"bytes,1,opt,name=server_cert,json=serverCert,proto3" json:"server_cert,omitempty"` ClientCert []byte `protobuf:"bytes,1,opt,name=client_cert,json=clientCert,proto3" json:"client_cert,omitempty"`
ClientCert []byte `protobuf:"bytes,2,opt,name=client_cert,json=clientCert,proto3" json:"client_cert,omitempty"` ClientKey []byte `protobuf:"bytes,2,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"`
ClientKey []byte `protobuf:"bytes,3,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"`
} }
func (x *LoginUserResponse) Reset() { func (x *LoginUserResponse) Reset() {
@ -886,13 +860,6 @@ func (*LoginUserResponse) Descriptor() ([]byte, []int) {
return file_protos_ezshare_proto_rawDescGZIP(), []int{14} return file_protos_ezshare_proto_rawDescGZIP(), []int{14}
} }
func (x *LoginUserResponse) GetServerCert() []byte {
if x != nil {
return x.ServerCert
}
return nil
}
func (x *LoginUserResponse) GetClientCert() []byte { func (x *LoginUserResponse) GetClientCert() []byte {
if x != nil { if x != nil {
return x.ClientCert return x.ClientCert
@ -1159,108 +1126,6 @@ func (x *ListFilesResponse_ListFileInfo) GetMetadata() *File_Metadata {
return nil return nil
} }
type LoginUserRequest_UserPasswordLogin struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
}
func (x *LoginUserRequest_UserPasswordLogin) Reset() {
*x = LoginUserRequest_UserPasswordLogin{}
if protoimpl.UnsafeEnabled {
mi := &file_protos_ezshare_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginUserRequest_UserPasswordLogin) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginUserRequest_UserPasswordLogin) ProtoMessage() {}
func (x *LoginUserRequest_UserPasswordLogin) ProtoReflect() protoreflect.Message {
mi := &file_protos_ezshare_proto_msgTypes[20]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginUserRequest_UserPasswordLogin.ProtoReflect.Descriptor instead.
func (*LoginUserRequest_UserPasswordLogin) Descriptor() ([]byte, []int) {
return file_protos_ezshare_proto_rawDescGZIP(), []int{13, 0}
}
func (x *LoginUserRequest_UserPasswordLogin) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *LoginUserRequest_UserPasswordLogin) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type LoginUserRequest_TokenLogin struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
}
func (x *LoginUserRequest_TokenLogin) Reset() {
*x = LoginUserRequest_TokenLogin{}
if protoimpl.UnsafeEnabled {
mi := &file_protos_ezshare_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LoginUserRequest_TokenLogin) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LoginUserRequest_TokenLogin) ProtoMessage() {}
func (x *LoginUserRequest_TokenLogin) ProtoReflect() protoreflect.Message {
mi := &file_protos_ezshare_proto_msgTypes[21]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LoginUserRequest_TokenLogin.ProtoReflect.Descriptor instead.
func (*LoginUserRequest_TokenLogin) Descriptor() ([]byte, []int) {
return file_protos_ezshare_proto_rawDescGZIP(), []int{13, 1}
}
func (x *LoginUserRequest_TokenLogin) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
var File_protos_ezshare_proto protoreflect.FileDescriptor var File_protos_ezshare_proto protoreflect.FileDescriptor
var file_protos_ezshare_proto_rawDesc = []byte{ var file_protos_ezshare_proto_rawDesc = []byte{
@ -1344,81 +1209,64 @@ var file_protos_ezshare_proto_rawDesc = []byte{
0x3c, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x3c, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb1, 0x02, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4a, 0x0a,
0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x73, 0x74, 0x12, 0x45, 0x0a, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a,
0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x74, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x53, 0x0a, 0x11, 0x4c, 0x6f, 0x67,
0x77, 0x69, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x52, 0x0a, 0x0d, 0x77, 0x69, 0x74, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f,
0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x01, 0x20,
0x32, 0x2b, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x12,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x12,
0x0c, 0x77, 0x69, 0x74, 0x68, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x1a, 0x4b, 0x0a, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x11, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x73, 0x74, 0x22, 0x38, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52,
0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65,
0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x2d, 0x0a, 0x12,
0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x1a, 0x22, 0x0a, 0x0a, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x11,
0x0a, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x69,
0x6e, 0x22, 0x74, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55,
0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x38, 0x0a, 0x11, 0x4c,
0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x23, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x0d, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05,
0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x2d, 0x0a, 0x12, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75,
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73,
0x65, 0x72, 0x49, 0x64, 0x32, 0xa5, 0x02, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69,
0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x55, 0x70, 0x6c,
0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b,
0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a,
0x07, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x17, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x18, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x46,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a,
0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x65, 0x7a,
0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72,
0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x69,
0x6c, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a,
0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x69, 0x6c,
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0x95, 0x02, 0x0a,
0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08,
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65,
0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x7a,
0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x4c, 0x69, 0x73,
0x74, 0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65,
0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x07, 0x41, 0x70,
0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x1b, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e,
0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x45, 0x6d, 0x70, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
0x74, 0x79, 0x22, 0x00, 0x42, 0x23, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x65, 0x61, 0x2e, 0x62, 0x65, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x32, 0xa5, 0x02, 0x0a, 0x0b,
0x6e, 0x6e, 0x79, 0x2e, 0x64, 0x6f, 0x67, 0x2f, 0x74, 0x6f, 0x72, 0x6a, 0x75, 0x73, 0x2f, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x55,
0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68,
0x33, 0x61, 0x72, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e,
0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12,
0x17, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x69,
0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b,
0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a,
0x09, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73,
0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x32, 0x95, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12,
0x1c, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40,
0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72,
0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x6f, 0x67,
0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x3f, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61,
0x72, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x38, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x1b, 0x2e, 0x65,
0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x55, 0x73,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x65, 0x7a, 0x73, 0x68,
0x61, 0x72, 0x65, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x23, 0x5a, 0x21, 0x67,
0x69, 0x74, 0x65, 0x61, 0x2e, 0x62, 0x65, 0x6e, 0x6e, 0x79, 0x2e, 0x64, 0x6f, 0x67, 0x2f, 0x74,
0x6f, 0x72, 0x6a, 0x75, 0x73, 0x2f, 0x65, 0x7a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x2f, 0x70, 0x62,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -1434,7 +1282,7 @@ func file_protos_ezshare_proto_rawDescGZIP() []byte {
} }
var file_protos_ezshare_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_protos_ezshare_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_protos_ezshare_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_protos_ezshare_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_protos_ezshare_proto_goTypes = []interface{}{ var file_protos_ezshare_proto_goTypes = []interface{}{
(User_Role)(0), // 0: ezshare.User.Role (User_Role)(0), // 0: ezshare.User.Role
(*Empty)(nil), // 1: ezshare.Empty (*Empty)(nil), // 1: ezshare.Empty
@ -1457,43 +1305,39 @@ var file_protos_ezshare_proto_goTypes = []interface{}{
(*ApproveUserRequest)(nil), // 18: ezshare.ApproveUserRequest (*ApproveUserRequest)(nil), // 18: ezshare.ApproveUserRequest
(*File_Metadata)(nil), // 19: ezshare.File.Metadata (*File_Metadata)(nil), // 19: ezshare.File.Metadata
(*ListFilesResponse_ListFileInfo)(nil), // 20: ezshare.ListFilesResponse.ListFileInfo (*ListFilesResponse_ListFileInfo)(nil), // 20: ezshare.ListFilesResponse.ListFileInfo
(*LoginUserRequest_UserPasswordLogin)(nil), // 21: ezshare.LoginUserRequest.UserPasswordLogin (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
(*LoginUserRequest_TokenLogin)(nil), // 22: ezshare.LoginUserRequest.TokenLogin
(*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp
} }
var file_protos_ezshare_proto_depIdxs = []int32{ var file_protos_ezshare_proto_depIdxs = []int32{
19, // 0: ezshare.File.metadata:type_name -> ezshare.File.Metadata 19, // 0: ezshare.File.metadata:type_name -> ezshare.File.Metadata
23, // 1: ezshare.UploadFileRequest.expires_on:type_name -> google.protobuf.Timestamp 21, // 1: ezshare.UploadFileRequest.expires_on:type_name -> google.protobuf.Timestamp
2, // 2: ezshare.GetFileResponse.file:type_name -> ezshare.File 2, // 2: ezshare.GetFileResponse.file:type_name -> ezshare.File
20, // 3: ezshare.ListFilesResponse.files:type_name -> ezshare.ListFilesResponse.ListFileInfo 20, // 3: ezshare.ListFilesResponse.files:type_name -> ezshare.ListFilesResponse.ListFileInfo
0, // 4: ezshare.User.user_role:type_name -> ezshare.User.Role 0, // 4: ezshare.User.user_role:type_name -> ezshare.User.Role
22, // 5: ezshare.LoginUserRequest.with_token:type_name -> ezshare.LoginUserRequest.TokenLogin 11, // 5: ezshare.ListUsersResponse.users:type_name -> ezshare.User
21, // 6: ezshare.LoginUserRequest.with_password:type_name -> ezshare.LoginUserRequest.UserPasswordLogin 21, // 6: ezshare.File.Metadata.uploaded_on:type_name -> google.protobuf.Timestamp
11, // 7: ezshare.ListUsersResponse.users:type_name -> ezshare.User 21, // 7: ezshare.File.Metadata.expires_on:type_name -> google.protobuf.Timestamp
23, // 8: ezshare.File.Metadata.uploaded_on:type_name -> google.protobuf.Timestamp 19, // 8: ezshare.ListFilesResponse.ListFileInfo.metadata:type_name -> ezshare.File.Metadata
23, // 9: ezshare.File.Metadata.expires_on:type_name -> google.protobuf.Timestamp 3, // 9: ezshare.FileService.UploadFile:input_type -> ezshare.UploadFileRequest
19, // 10: ezshare.ListFilesResponse.ListFileInfo.metadata:type_name -> ezshare.File.Metadata 5, // 10: ezshare.FileService.GetFile:input_type -> ezshare.GetFileRequest
3, // 11: ezshare.FileService.UploadFile:input_type -> ezshare.UploadFileRequest 7, // 11: ezshare.FileService.DeleteFile:input_type -> ezshare.DeleteFileRequest
5, // 12: ezshare.FileService.GetFile:input_type -> ezshare.GetFileRequest 9, // 12: ezshare.FileService.ListFiles:input_type -> ezshare.ListFilesRequest
7, // 13: ezshare.FileService.DeleteFile:input_type -> ezshare.DeleteFileRequest 12, // 13: ezshare.UserService.Register:input_type -> ezshare.RegisterUserRequest
9, // 14: ezshare.FileService.ListFiles:input_type -> ezshare.ListFilesRequest 14, // 14: ezshare.UserService.Login:input_type -> ezshare.LoginUserRequest
12, // 15: ezshare.UserService.Register:input_type -> ezshare.RegisterUserRequest 16, // 15: ezshare.UserService.List:input_type -> ezshare.ListUsersRequest
14, // 16: ezshare.UserService.Login:input_type -> ezshare.LoginUserRequest 18, // 16: ezshare.UserService.Approve:input_type -> ezshare.ApproveUserRequest
16, // 17: ezshare.UserService.List:input_type -> ezshare.ListUsersRequest 4, // 17: ezshare.FileService.UploadFile:output_type -> ezshare.UploadFileResponse
18, // 18: ezshare.UserService.Approve:input_type -> ezshare.ApproveUserRequest 6, // 18: ezshare.FileService.GetFile:output_type -> ezshare.GetFileResponse
4, // 19: ezshare.FileService.UploadFile:output_type -> ezshare.UploadFileResponse 8, // 19: ezshare.FileService.DeleteFile:output_type -> ezshare.DeleteFileResponse
6, // 20: ezshare.FileService.GetFile:output_type -> ezshare.GetFileResponse 10, // 20: ezshare.FileService.ListFiles:output_type -> ezshare.ListFilesResponse
8, // 21: ezshare.FileService.DeleteFile:output_type -> ezshare.DeleteFileResponse 13, // 21: ezshare.UserService.Register:output_type -> ezshare.RegisterUserResponse
10, // 22: ezshare.FileService.ListFiles:output_type -> ezshare.ListFilesResponse 15, // 22: ezshare.UserService.Login:output_type -> ezshare.LoginUserResponse
13, // 23: ezshare.UserService.Register:output_type -> ezshare.RegisterUserResponse 17, // 23: ezshare.UserService.List:output_type -> ezshare.ListUsersResponse
15, // 24: ezshare.UserService.Login:output_type -> ezshare.LoginUserResponse 1, // 24: ezshare.UserService.Approve:output_type -> ezshare.Empty
17, // 25: ezshare.UserService.List:output_type -> ezshare.ListUsersResponse 17, // [17:25] is the sub-list for method output_type
1, // 26: ezshare.UserService.Approve:output_type -> ezshare.Empty 9, // [9:17] is the sub-list for method input_type
19, // [19:27] is the sub-list for method output_type 9, // [9:9] is the sub-list for extension type_name
11, // [11:19] is the sub-list for method input_type 9, // [9:9] is the sub-list for extension extendee
11, // [11:11] is the sub-list for extension type_name 0, // [0:9] is the sub-list for field type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
} }
func init() { file_protos_ezshare_proto_init() } func init() { file_protos_ezshare_proto_init() }
@ -1742,34 +1586,6 @@ func file_protos_ezshare_proto_init() {
return nil return nil
} }
} }
file_protos_ezshare_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginUserRequest_UserPasswordLogin); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protos_ezshare_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginUserRequest_TokenLogin); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_protos_ezshare_proto_msgTypes[13].OneofWrappers = []interface{}{
(*LoginUserRequest_WithToken)(nil),
(*LoginUserRequest_WithPassword)(nil),
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@ -1777,7 +1593,7 @@ func file_protos_ezshare_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_protos_ezshare_proto_rawDesc, RawDescriptor: file_protos_ezshare_proto_rawDesc,
NumEnums: 1, NumEnums: 1,
NumMessages: 22, NumMessages: 20,
NumExtensions: 0, NumExtensions: 0,
NumServices: 2, NumServices: 2,
}, },

View File

@ -101,23 +101,12 @@ message RegisterUserResponse {
// Login // Login
message LoginUserRequest { message LoginUserRequest {
message UserPasswordLogin {
string username = 1; string username = 1;
string password = 2; string password = 2;
} }
message TokenLogin {
string token = 1;
}
oneof requested_login {
TokenLogin with_token = 1;
UserPasswordLogin with_password = 2;
}
}
message LoginUserResponse { message LoginUserResponse {
bytes server_cert = 1; bytes client_cert = 1;
bytes client_cert = 2; bytes client_key = 2;
bytes client_key = 3;
} }
// List // List

View File

@ -11,22 +11,43 @@ import (
type HTTPServer struct { type HTTPServer struct {
store store.FileStore store store.FileStore
serverGRPCCert []byte
grpcEndpoint string
http.Server http.Server
} }
func NewHTTPSever(store store.FileStore) *HTTPServer { type MetadataResponse struct {
GRPCEndpoint string `json:"grpc_endpoint"`
}
func NewHTTPSever(store store.FileStore, certBytes []byte, grpcEndpoint string) *HTTPServer {
srv := &HTTPServer{ srv := &HTTPServer{
store: store, store: store,
serverGRPCCert: certBytes,
grpcEndpoint: grpcEndpoint,
} }
r := chi.NewRouter() r := chi.NewRouter()
r.Get("/server.pem", srv.ServerCertHandler)
r.Get("/metadata", srv.MetadataHandler)
r.Get("/files/{id}", srv.FileHandler) r.Get("/files/{id}", srv.FileHandler)
srv.Handler = r srv.Handler = r
return srv return srv
} }
func (s *HTTPServer) ServerCertHandler(w http.ResponseWriter, r *http.Request) {
w.Write(s.serverGRPCCert)
}
func (s *HTTPServer) MetadataHandler(w http.ResponseWriter, r *http.Request) {
md := &MetadataResponse{
GRPCEndpoint: s.grpcEndpoint,
}
encoder := json.NewEncoder(w)
encoder.Encode(md)
}
func (s *HTTPServer) FileHandler(w http.ResponseWriter, r *http.Request) { func (s *HTTPServer) FileHandler(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id") id := chi.URLParam(r, "id")
f, err := s.store.GetFile(id) f, err := s.store.GetFile(id)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"gitea.benny.dog/torjus/ezshare/certs"
"gitea.benny.dog/torjus/ezshare/pb" "gitea.benny.dog/torjus/ezshare/pb"
"gitea.benny.dog/torjus/ezshare/store" "gitea.benny.dog/torjus/ezshare/store"
"github.com/google/uuid" "github.com/google/uuid"
@ -14,16 +15,17 @@ import (
type GRPCUserServiceServer struct { type GRPCUserServiceServer struct {
store store.UserStore store store.UserStore
certService *certs.CertService
pb.UnimplementedUserServiceServer pb.UnimplementedUserServiceServer
} }
func NewGRPCUserServiceServer(store store.UserStore) *GRPCUserServiceServer { func NewGRPCUserServiceServer(store store.UserStore, certSvc *certs.CertService) *GRPCUserServiceServer {
return &GRPCUserServiceServer{store: store} return &GRPCUserServiceServer{store: store, certService: certSvc}
} }
func (s *GRPCUserServiceServer) Register(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) { func (s *GRPCUserServiceServer) Register(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) {
// Check if user already exists // Check if user already exists
if _, err := s.store.GetUserByUsername(req.Username); err != store.ErrNoSuchItem { if _, err := s.store.GetUserByUsername(req.Username); err != store.ErrNoSuchItem {
return nil, fmt.Errorf("user already exists") return nil, status.Error(codes.AlreadyExists, "user already exists")
} }
pw, err := hashPassword(req.Password) pw, err := hashPassword(req.Password)
@ -45,8 +47,30 @@ func (s *GRPCUserServiceServer) Register(ctx context.Context, req *pb.RegisterUs
return &pb.RegisterUserResponse{Id: user.Id, Token: ""}, nil return &pb.RegisterUserResponse{Id: user.Id, Token: ""}, nil
} }
func (s *GRPCUserServiceServer) Login(_ context.Context, _ *pb.LoginUserRequest) (*pb.LoginUserResponse, error) { func (s *GRPCUserServiceServer) Login(_ context.Context, req *pb.LoginUserRequest) (*pb.LoginUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "not yet implemented") user, err := s.store.GetUserByUsername(req.Username)
if err != nil {
if err == store.ErrNoSuchItem {
return nil, status.Error(codes.NotFound, "no such user")
}
return nil, status.Error(codes.Internal, "error getting user from store")
}
if err := bcrypt.CompareHashAndPassword(user.HashedPassword, []byte(req.Password)); err != nil {
return nil, status.Error(codes.Unauthenticated, "wrong username and or password")
}
cert, key, err := s.certService.NewClient(user.Id)
if err != nil {
return nil, status.Error(codes.Internal, "unable to generate client certificate")
}
resp := &pb.LoginUserResponse{
ClientCert: cert,
ClientKey: key,
}
return resp, nil
} }
func (s *GRPCUserServiceServer) List(_ context.Context, _ *pb.ListUsersRequest) (*pb.ListUsersResponse, error) { func (s *GRPCUserServiceServer) List(_ context.Context, _ *pb.ListUsersRequest) (*pb.ListUsersResponse, error) {

View File

@ -1,3 +0,0 @@
package ezshare
const Version = "v0.1.1"