diff --git a/actions/client.go b/actions/client.go new file mode 100644 index 0000000..896ae2f --- /dev/null +++ b/actions/client.go @@ -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 +} diff --git a/actions/misc.go b/actions/misc.go new file mode 100644 index 0000000..c1ae146 --- /dev/null +++ b/actions/misc.go @@ -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) + } +} diff --git a/actions/serve.go b/actions/serve.go new file mode 100644 index 0000000..207c529 --- /dev/null +++ b/actions/serve.go @@ -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 +} diff --git a/certs/generate.go b/certs/generate.go index 0d9f3ff..21037d1 100644 --- a/certs/generate.go +++ b/certs/generate.go @@ -15,6 +15,19 @@ import ( "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 { // Convert to PEM certPEM := new(bytes.Buffer) diff --git a/cmd/ezshare.go b/cmd/ezshare.go deleted file mode 100644 index 3b8bcff..0000000 --- a/cmd/ezshare.go +++ /dev/null @@ -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) - } -} diff --git a/config/config.go b/config/config.go index 9928924..3dc8035 100644 --- a/config/config.go +++ b/config/config.go @@ -17,6 +17,8 @@ import ( "google.golang.org/grpc/credentials" ) +var ErrNotFound = fmt.Errorf("config not found") + type Config struct { Server *ServerConfig `toml:"Server"` Client *ClientConfig `toml:"Client"` @@ -28,19 +30,26 @@ type CertificatePaths struct { } type ServerConfig struct { - LogLevel string `toml:"LogLevel"` - Hostname string `toml:"Hostname"` - StoreConfig *ServerStoreConfig `toml:"Store"` - GRPC *ServerGRPCConfig `toml:"GRPC"` - HTTP *ServerHTTPConfig `toml:"HTTP"` + LogLevel string `toml:"LogLevel"` + Hostname string `toml:"Hostname"` + GRPCEndpoint string `toml:"GRPCEndpoint"` + UserStoreConfig *ServerUserStoreConfig `toml:"UserStore"` + FileStoreConfig *ServerFileStoreConfig `toml:"FileStore"` + GRPC *ServerGRPCConfig `toml:"GRPC"` + HTTP *ServerHTTPConfig `toml:"HTTP"` } -type ServerStoreConfig struct { +type ServerFileStoreConfig struct { Type string `toml:"Type"` FSStoreConfig *FSStoreConfig `toml:"Filesystem"` BoltStoreConfig *BoltStoreConfig `toml:"Bolt"` } +type ServerUserStoreConfig struct { + Type string `toml:"Type"` + BoltStoreConfig *BoltStoreConfig `toml:"Bolt"` +} + type BoltStoreConfig struct { Path string `toml:"Path"` } @@ -78,7 +87,9 @@ func FromDefault() *Config { ListenAddr: ":8089", }, }, - Client: &ClientConfig{}, + Client: &ClientConfig{ + Certs: &CertificatePaths{}, + }, } return cfg @@ -97,6 +108,9 @@ func FromReader(r io.Reader) (*Config, error) { func FromFile(path string) (*Config, error) { f, err := os.Open(path) if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil, ErrNotFound + } return nil, fmt.Errorf("unable to open config-file: %w", err) } defer f.Close() @@ -188,7 +202,7 @@ func (cc *ClientConfig) Creds() (credentials.TransportCredentials, error) { return credentials.NewTLS(config), nil } -func (c *Config) ToDefaultFile() error { +func CreateDefaultConfigDir() error { userConfigDir, err := os.UserConfigDir() if err != nil { return err @@ -207,8 +221,25 @@ func (c *Config) ToDefaultFile() error { 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) if err != nil { if !errors.Is(err, fs.ErrNotExist) { @@ -226,7 +257,7 @@ func (c *Config) ToDefaultFile() error { 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 } if strings.EqualFold(sc.Type, "bolt") { 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") { 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") } diff --git a/ezshare.example.toml b/ezshare.example.toml index 0b9769d..584877d 100644 --- a/ezshare.example.toml +++ b/ezshare.example.toml @@ -12,23 +12,38 @@ LogLevel = "INFO" # Required Hostname = "localhost" -# Storage configuration -[Server.Store] +# Endpoint reachable by clients +# Fetched by clients for automatic setup +# Required +GRPCEndpoint = "localhost:50051" + +# File store configuration +[Server.FileStore] # How server stores file # Must be one of: filesystem, memory, bolt # Required -Type = "filesystem" +Type = "bolt" -[Server.Store.Bolt] +[Server.FileStore.Bolt] # Where the bolt-db is stored # Required if store-type is bolt -Path = "" +Path = "/data/files.db" -[Server.Store.Filesystem] +[Server.FileStore.Filesystem] # Where files are stored # Required if store-type is filesystem 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 [Server.GRPC] # Address to listen to diff --git a/go.mod b/go.mod index 124e782..f9f86e0 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/urfave/cli/v2 v2.3.0 go.etcd.io/bbolt v1.3.6 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/protobuf v1.27.1 ) @@ -19,7 +20,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // 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/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9 // indirect diff --git a/go.sum b/go.sum index 6c7139d..082ef6c 100644 --- a/go.sum +++ b/go.sum @@ -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-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-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= +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-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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..9b074fa --- /dev/null +++ b/main.go @@ -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) + } + +} diff --git a/pb/ezshare.pb.go b/pb/ezshare.pb.go index 3af0c12..28726be 100644 --- a/pb/ezshare.pb.go +++ b/pb/ezshare.pb.go @@ -769,10 +769,8 @@ type LoginUserRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Types that are assignable to RequestedLogin: - // *LoginUserRequest_WithToken - // *LoginUserRequest_WithPassword - RequestedLogin isLoginUserRequest_RequestedLogin `protobuf_oneof:"requested_login"` + 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) Reset() { @@ -807,51 +805,27 @@ func (*LoginUserRequest) Descriptor() ([]byte, []int) { return file_protos_ezshare_proto_rawDescGZIP(), []int{13} } -func (m *LoginUserRequest) GetRequestedLogin() isLoginUserRequest_RequestedLogin { - if m != nil { - return m.RequestedLogin +func (x *LoginUserRequest) GetUsername() string { + if x != nil { + return x.Username } - return nil + return "" } -func (x *LoginUserRequest) GetWithToken() *LoginUserRequest_TokenLogin { - if x, ok := x.GetRequestedLogin().(*LoginUserRequest_WithToken); ok { - return x.WithToken +func (x *LoginUserRequest) GetPassword() string { + if x != nil { + 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 { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ServerCert []byte `protobuf:"bytes,1,opt,name=server_cert,json=serverCert,proto3" json:"server_cert,omitempty"` - ClientCert []byte `protobuf:"bytes,2,opt,name=client_cert,json=clientCert,proto3" json:"client_cert,omitempty"` - ClientKey []byte `protobuf:"bytes,3,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"` + ClientCert []byte `protobuf:"bytes,1,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"` } func (x *LoginUserResponse) Reset() { @@ -886,13 +860,6 @@ func (*LoginUserResponse) Descriptor() ([]byte, []int) { 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 { if x != nil { return x.ClientCert @@ -1159,108 +1126,6 @@ func (x *ListFilesResponse_ListFileInfo) GetMetadata() *File_Metadata { 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_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, 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, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb1, 0x02, - 0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x45, 0x0a, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 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, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x48, 0x00, 0x52, 0x09, - 0x77, 0x69, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x52, 0x0a, 0x0d, 0x77, 0x69, 0x74, - 0x68, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 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, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x48, 0x00, 0x52, - 0x0c, 0x77, 0x69, 0x74, 0x68, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x1a, 0x4b, 0x0a, - 0x11, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 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, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4a, 0x0a, + 0x10, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x53, 0x0a, 0x11, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x01, 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, 0x02, 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, 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, + 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, 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 ( @@ -1434,66 +1282,62 @@ func file_protos_ezshare_proto_rawDescGZIP() []byte { } 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{}{ - (User_Role)(0), // 0: ezshare.User.Role - (*Empty)(nil), // 1: ezshare.Empty - (*File)(nil), // 2: ezshare.File - (*UploadFileRequest)(nil), // 3: ezshare.UploadFileRequest - (*UploadFileResponse)(nil), // 4: ezshare.UploadFileResponse - (*GetFileRequest)(nil), // 5: ezshare.GetFileRequest - (*GetFileResponse)(nil), // 6: ezshare.GetFileResponse - (*DeleteFileRequest)(nil), // 7: ezshare.DeleteFileRequest - (*DeleteFileResponse)(nil), // 8: ezshare.DeleteFileResponse - (*ListFilesRequest)(nil), // 9: ezshare.ListFilesRequest - (*ListFilesResponse)(nil), // 10: ezshare.ListFilesResponse - (*User)(nil), // 11: ezshare.User - (*RegisterUserRequest)(nil), // 12: ezshare.RegisterUserRequest - (*RegisterUserResponse)(nil), // 13: ezshare.RegisterUserResponse - (*LoginUserRequest)(nil), // 14: ezshare.LoginUserRequest - (*LoginUserResponse)(nil), // 15: ezshare.LoginUserResponse - (*ListUsersRequest)(nil), // 16: ezshare.ListUsersRequest - (*ListUsersResponse)(nil), // 17: ezshare.ListUsersResponse - (*ApproveUserRequest)(nil), // 18: ezshare.ApproveUserRequest - (*File_Metadata)(nil), // 19: ezshare.File.Metadata - (*ListFilesResponse_ListFileInfo)(nil), // 20: ezshare.ListFilesResponse.ListFileInfo - (*LoginUserRequest_UserPasswordLogin)(nil), // 21: ezshare.LoginUserRequest.UserPasswordLogin - (*LoginUserRequest_TokenLogin)(nil), // 22: ezshare.LoginUserRequest.TokenLogin - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp + (User_Role)(0), // 0: ezshare.User.Role + (*Empty)(nil), // 1: ezshare.Empty + (*File)(nil), // 2: ezshare.File + (*UploadFileRequest)(nil), // 3: ezshare.UploadFileRequest + (*UploadFileResponse)(nil), // 4: ezshare.UploadFileResponse + (*GetFileRequest)(nil), // 5: ezshare.GetFileRequest + (*GetFileResponse)(nil), // 6: ezshare.GetFileResponse + (*DeleteFileRequest)(nil), // 7: ezshare.DeleteFileRequest + (*DeleteFileResponse)(nil), // 8: ezshare.DeleteFileResponse + (*ListFilesRequest)(nil), // 9: ezshare.ListFilesRequest + (*ListFilesResponse)(nil), // 10: ezshare.ListFilesResponse + (*User)(nil), // 11: ezshare.User + (*RegisterUserRequest)(nil), // 12: ezshare.RegisterUserRequest + (*RegisterUserResponse)(nil), // 13: ezshare.RegisterUserResponse + (*LoginUserRequest)(nil), // 14: ezshare.LoginUserRequest + (*LoginUserResponse)(nil), // 15: ezshare.LoginUserResponse + (*ListUsersRequest)(nil), // 16: ezshare.ListUsersRequest + (*ListUsersResponse)(nil), // 17: ezshare.ListUsersResponse + (*ApproveUserRequest)(nil), // 18: ezshare.ApproveUserRequest + (*File_Metadata)(nil), // 19: ezshare.File.Metadata + (*ListFilesResponse_ListFileInfo)(nil), // 20: ezshare.ListFilesResponse.ListFileInfo + (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } var file_protos_ezshare_proto_depIdxs = []int32{ 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 20, // 3: ezshare.ListFilesResponse.files:type_name -> ezshare.ListFilesResponse.ListFileInfo 0, // 4: ezshare.User.user_role:type_name -> ezshare.User.Role - 22, // 5: ezshare.LoginUserRequest.with_token:type_name -> ezshare.LoginUserRequest.TokenLogin - 21, // 6: ezshare.LoginUserRequest.with_password:type_name -> ezshare.LoginUserRequest.UserPasswordLogin - 11, // 7: ezshare.ListUsersResponse.users:type_name -> ezshare.User - 23, // 8: ezshare.File.Metadata.uploaded_on:type_name -> google.protobuf.Timestamp - 23, // 9: ezshare.File.Metadata.expires_on:type_name -> google.protobuf.Timestamp - 19, // 10: ezshare.ListFilesResponse.ListFileInfo.metadata:type_name -> ezshare.File.Metadata - 3, // 11: ezshare.FileService.UploadFile:input_type -> ezshare.UploadFileRequest - 5, // 12: ezshare.FileService.GetFile:input_type -> ezshare.GetFileRequest - 7, // 13: ezshare.FileService.DeleteFile:input_type -> ezshare.DeleteFileRequest - 9, // 14: ezshare.FileService.ListFiles:input_type -> ezshare.ListFilesRequest - 12, // 15: ezshare.UserService.Register:input_type -> ezshare.RegisterUserRequest - 14, // 16: ezshare.UserService.Login:input_type -> ezshare.LoginUserRequest - 16, // 17: ezshare.UserService.List:input_type -> ezshare.ListUsersRequest - 18, // 18: ezshare.UserService.Approve:input_type -> ezshare.ApproveUserRequest - 4, // 19: ezshare.FileService.UploadFile:output_type -> ezshare.UploadFileResponse - 6, // 20: ezshare.FileService.GetFile:output_type -> ezshare.GetFileResponse - 8, // 21: ezshare.FileService.DeleteFile:output_type -> ezshare.DeleteFileResponse - 10, // 22: ezshare.FileService.ListFiles:output_type -> ezshare.ListFilesResponse - 13, // 23: ezshare.UserService.Register:output_type -> ezshare.RegisterUserResponse - 15, // 24: ezshare.UserService.Login:output_type -> ezshare.LoginUserResponse - 17, // 25: ezshare.UserService.List:output_type -> ezshare.ListUsersResponse - 1, // 26: ezshare.UserService.Approve:output_type -> ezshare.Empty - 19, // [19:27] is the sub-list for method output_type - 11, // [11:19] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 11, // 5: ezshare.ListUsersResponse.users:type_name -> ezshare.User + 21, // 6: ezshare.File.Metadata.uploaded_on:type_name -> google.protobuf.Timestamp + 21, // 7: ezshare.File.Metadata.expires_on:type_name -> google.protobuf.Timestamp + 19, // 8: ezshare.ListFilesResponse.ListFileInfo.metadata:type_name -> ezshare.File.Metadata + 3, // 9: ezshare.FileService.UploadFile:input_type -> ezshare.UploadFileRequest + 5, // 10: ezshare.FileService.GetFile:input_type -> ezshare.GetFileRequest + 7, // 11: ezshare.FileService.DeleteFile:input_type -> ezshare.DeleteFileRequest + 9, // 12: ezshare.FileService.ListFiles:input_type -> ezshare.ListFilesRequest + 12, // 13: ezshare.UserService.Register:input_type -> ezshare.RegisterUserRequest + 14, // 14: ezshare.UserService.Login:input_type -> ezshare.LoginUserRequest + 16, // 15: ezshare.UserService.List:input_type -> ezshare.ListUsersRequest + 18, // 16: ezshare.UserService.Approve:input_type -> ezshare.ApproveUserRequest + 4, // 17: ezshare.FileService.UploadFile:output_type -> ezshare.UploadFileResponse + 6, // 18: ezshare.FileService.GetFile:output_type -> ezshare.GetFileResponse + 8, // 19: ezshare.FileService.DeleteFile:output_type -> ezshare.DeleteFileResponse + 10, // 20: ezshare.FileService.ListFiles:output_type -> ezshare.ListFilesResponse + 13, // 21: ezshare.UserService.Register:output_type -> ezshare.RegisterUserResponse + 15, // 22: ezshare.UserService.Login:output_type -> ezshare.LoginUserResponse + 17, // 23: ezshare.UserService.List:output_type -> ezshare.ListUsersResponse + 1, // 24: ezshare.UserService.Approve:output_type -> ezshare.Empty + 17, // [17:25] is the sub-list for method output_type + 9, // [9:17] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_protos_ezshare_proto_init() } @@ -1742,34 +1586,6 @@ func file_protos_ezshare_proto_init() { 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{} out := protoimpl.TypeBuilder{ @@ -1777,7 +1593,7 @@ func file_protos_ezshare_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_protos_ezshare_proto_rawDesc, NumEnums: 1, - NumMessages: 22, + NumMessages: 20, NumExtensions: 0, NumServices: 2, }, diff --git a/protos/ezshare.proto b/protos/ezshare.proto index 84192fb..53d52d5 100644 --- a/protos/ezshare.proto +++ b/protos/ezshare.proto @@ -101,23 +101,12 @@ message RegisterUserResponse { // Login message LoginUserRequest { - message UserPasswordLogin { - string username = 1; - string password = 2; - } - message TokenLogin { - string token = 1; - } - - oneof requested_login { - TokenLogin with_token = 1; - UserPasswordLogin with_password = 2; - } + string username = 1; + string password = 2; } message LoginUserResponse { - bytes server_cert = 1; - bytes client_cert = 2; - bytes client_key = 3; + bytes client_cert = 1; + bytes client_key = 2; } // List diff --git a/server/http.go b/server/http.go index e244636..29eb47c 100644 --- a/server/http.go +++ b/server/http.go @@ -10,23 +10,44 @@ import ( ) type HTTPServer struct { - store store.FileStore + store store.FileStore + serverGRPCCert []byte + grpcEndpoint string 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{ - store: store, + store: store, + serverGRPCCert: certBytes, + grpcEndpoint: grpcEndpoint, } r := chi.NewRouter() + r.Get("/server.pem", srv.ServerCertHandler) + r.Get("/metadata", srv.MetadataHandler) r.Get("/files/{id}", srv.FileHandler) srv.Handler = r 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) { id := chi.URLParam(r, "id") f, err := s.store.GetFile(id) diff --git a/server/userservice.go b/server/userservice.go index ffacdc9..a75d438 100644 --- a/server/userservice.go +++ b/server/userservice.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "gitea.benny.dog/torjus/ezshare/certs" "gitea.benny.dog/torjus/ezshare/pb" "gitea.benny.dog/torjus/ezshare/store" "github.com/google/uuid" @@ -13,17 +14,18 @@ import ( ) type GRPCUserServiceServer struct { - store store.UserStore + store store.UserStore + certService *certs.CertService pb.UnimplementedUserServiceServer } -func NewGRPCUserServiceServer(store store.UserStore) *GRPCUserServiceServer { - return &GRPCUserServiceServer{store: store} +func NewGRPCUserServiceServer(store store.UserStore, certSvc *certs.CertService) *GRPCUserServiceServer { + return &GRPCUserServiceServer{store: store, certService: certSvc} } func (s *GRPCUserServiceServer) Register(ctx context.Context, req *pb.RegisterUserRequest) (*pb.RegisterUserResponse, error) { // Check if user already exists 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) @@ -45,8 +47,30 @@ func (s *GRPCUserServiceServer) Register(ctx context.Context, req *pb.RegisterUs return &pb.RegisterUserResponse{Id: user.Id, Token: ""}, nil } -func (s *GRPCUserServiceServer) Login(_ context.Context, _ *pb.LoginUserRequest) (*pb.LoginUserResponse, error) { - return nil, status.Error(codes.Unimplemented, "not yet implemented") +func (s *GRPCUserServiceServer) Login(_ context.Context, req *pb.LoginUserRequest) (*pb.LoginUserResponse, error) { + 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) { diff --git a/version.go b/version.go deleted file mode 100644 index 99d250a..0000000 --- a/version.go +++ /dev/null @@ -1,3 +0,0 @@ -package ezshare - -const Version = "v0.1.1"