ezshare/server/fileservice.go

148 lines
4.4 KiB
Go
Raw Normal View History

2021-12-03 22:04:09 +00:00
package server
import (
"context"
"fmt"
2021-12-06 19:13:04 +00:00
"time"
2021-12-03 22:04:09 +00:00
2022-01-13 17:40:15 +00:00
"git.t-juice.club/torjus/ezshare/pb"
"git.t-juice.club/torjus/ezshare/server/interceptors"
"git.t-juice.club/torjus/ezshare/store"
2021-12-06 06:55:30 +00:00
"github.com/dustin/go-humanize"
2021-12-06 19:13:04 +00:00
"github.com/google/uuid"
2021-12-06 06:55:30 +00:00
"go.uber.org/zap"
2021-12-06 19:13:04 +00:00
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
2021-12-03 22:04:09 +00:00
)
type GRPCFileServiceServer struct {
2021-12-06 06:55:30 +00:00
Logger *zap.SugaredLogger
2021-12-03 22:04:09 +00:00
Hostname string
store store.FileStore
pb.UnimplementedFileServiceServer
}
func NewGRPCFileServiceServer(store store.FileStore) *GRPCFileServiceServer {
2021-12-06 06:55:30 +00:00
return &GRPCFileServiceServer{Hostname: "localhost:8051", store: store, Logger: zap.NewNop().Sugar()}
2021-12-03 22:04:09 +00:00
}
func (s *GRPCFileServiceServer) UploadFile(ctx context.Context, req *pb.UploadFileRequest) (*pb.UploadFileResponse, error) {
2021-12-07 05:51:14 +00:00
// Check if authorized
if !interceptors.RoleAtLeast(ctx, pb.User_USER) {
return nil, status.Error(codes.PermissionDenied, "permission denied")
}
2021-12-03 22:04:09 +00:00
var f pb.File
f.Data = req.GetData()
2021-12-06 19:13:04 +00:00
f.Metadata = &pb.File_Metadata{}
f.Metadata.OriginalFilename = req.OriginalFilename
if req.WithPasscode {
f.Metadata.Passcode = uuid.Must(uuid.NewRandom()).String()
}
f.Metadata.ExpiresOn = req.ExpiresOn
f.Metadata.MaxViews = req.MaxViews
2021-12-03 22:04:09 +00:00
id, err := s.store.StoreFile(&f)
if err != nil {
2021-12-06 06:55:30 +00:00
s.Logger.Warnw("Error storing file.", "error", err)
2021-12-03 22:04:09 +00:00
return nil, err
}
2021-12-06 19:13:04 +00:00
fileUrl := fmt.Sprintf("%s/files/%s", s.Hostname, id)
if req.WithPasscode {
fileUrl = fmt.Sprintf("%s?passcode=%s", fileUrl, f.Metadata.Passcode)
}
2021-12-06 06:55:30 +00:00
s.Logger.Infow("Received file.", "id", id, "size", humanize.Bytes(uint64(len(f.Data))))
2021-12-06 19:13:04 +00:00
return &pb.UploadFileResponse{Id: id, FileUrl: fileUrl}, nil
2021-12-03 22:04:09 +00:00
}
func (s *GRPCFileServiceServer) GetFile(ctx context.Context, req *pb.GetFileRequest) (*pb.GetFileResponse, error) {
f, err := s.store.GetFile(req.Id)
if err != nil {
return nil, err
}
2021-12-06 19:13:04 +00:00
// Check if expired, viewed too many times, or needs passcode
if f.Metadata.ExpiresOn != nil {
if f.Metadata.ExpiresOn.AsTime().Before(time.Now()) {
if err := s.store.DeleteFile(f.FileId); err != nil {
s.Logger.Warnw("Error deleting expired file.", "error", err)
}
return nil, status.Error(codes.NotFound, "no such file")
}
}
// Check if requires passcode
if f.Metadata.Passcode != "" {
if f.Metadata.Passcode != req.Passcode {
return nil, status.Error(codes.PermissionDenied, "needs passcode")
}
}
// Too many views
if f.Metadata.MaxViews != 0 {
if f.Metadata.CurrentViews >= f.Metadata.MaxViews {
if err := s.store.DeleteFile(f.FileId); err != nil {
s.Logger.Warnw("Error deleting expired file.", "error", err)
}
return nil, status.Error(codes.NotFound, "no such file")
}
}
f.Metadata.CurrentViews++
if _, err := s.store.StoreFile(f); err != nil {
s.Logger.Warnw("Error storing updated file.", "error", err)
}
s.Logger.Infow("Sending file to client.", "id", f.FileId, "size", humanize.Bytes(uint64(len(f.Data))))
2021-12-03 22:04:09 +00:00
return &pb.GetFileResponse{File: f}, nil
}
2021-12-04 10:30:42 +00:00
func (s *GRPCFileServiceServer) DeleteFile(ctx context.Context, req *pb.DeleteFileRequest) (*pb.DeleteFileResponse, error) {
2021-12-07 05:51:14 +00:00
// Check if authorized
if !interceptors.RoleAtLeast(ctx, pb.User_USER) {
return nil, status.Error(codes.PermissionDenied, "permission denied")
}
// Ensure owner of file or admin
f, err := s.store.GetFile(req.Id)
if err != nil {
2021-12-08 14:49:02 +00:00
if err == store.ErrNoSuchItem {
return nil, status.Error(codes.NotFound, "no such file")
}
2021-12-07 05:51:14 +00:00
s.Logger.Warnw("Error getting file.", "error", err)
2021-12-08 14:49:02 +00:00
return nil, status.Errorf(codes.Internal, "error getting file: %s", err)
2021-12-07 05:51:14 +00:00
}
if !(f.Metadata.Owner == interceptors.UserIDFromContext(ctx) || interceptors.RoleFromContext(ctx) == pb.User_ADMIN) {
return nil, status.Error(codes.PermissionDenied, "permission denied")
}
2021-12-06 06:55:30 +00:00
if err := s.store.DeleteFile(req.Id); err != nil {
s.Logger.Warnw("Error deleting file.", "error", err)
return nil, err
}
s.Logger.Infow("Deleted file.", "id", req.Id)
return &pb.DeleteFileResponse{}, nil
2021-12-04 10:30:42 +00:00
}
func (s *GRPCFileServiceServer) ListFiles(ctx context.Context, req *pb.ListFilesRequest) (*pb.ListFilesResponse, error) {
2021-12-07 05:51:14 +00:00
var infos []*pb.ListFilesResponse_ListFileInfo
allInfos, err := s.store.ListFiles()
2021-12-04 10:30:42 +00:00
if err != nil {
return nil, err
}
2021-12-07 05:51:14 +00:00
if interceptors.RoleFromContext(ctx) == pb.User_ADMIN {
return &pb.ListFilesResponse{Files: allInfos}, nil
}
ownerID := interceptors.UserIDFromContext(ctx)
for _, info := range allInfos {
if info.Metadata.Owner == ownerID {
infos = append(infos, info)
}
}
2021-12-04 10:30:42 +00:00
return &pb.ListFilesResponse{
Files: infos,
}, nil
}