generated from VLADIMIR/template
68 lines
2.3 KiB
Go
68 lines
2.3 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"evening_detective_server/internal/modules/roles"
|
|
"evening_detective_server/internal/services/file_service"
|
|
proto "evening_detective_server/proto"
|
|
|
|
"google.golang.org/genproto/googleapis/api/httpbody"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/metadata"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
func (s *server) UploadFile(ctx context.Context, req *proto.UploadFileReq) (*proto.UploadFileRsp, error) {
|
|
// Файлы (в т.ч. улики) загружают авторы сценариев в редакторе.
|
|
claims, claimsErr := claimsFromContext(ctx)
|
|
if claimsErr != nil {
|
|
return nil, claimsErr
|
|
}
|
|
if !roles.HasRole(claims, roles.Author) {
|
|
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
|
}
|
|
|
|
filename, fileType, err := s.fileService.UploadFile(ctx, req.Filename, req.Data)
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, file_service.ErrFileTooLarge):
|
|
return nil, status.Errorf(codes.ResourceExhausted, "%v", err)
|
|
case errors.Is(err, file_service.ErrEmptyName),
|
|
errors.Is(err, file_service.ErrEmptyData),
|
|
errors.Is(err, file_service.ErrInvalidExtension),
|
|
errors.Is(err, file_service.ErrInvalidContentType):
|
|
return nil, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
default:
|
|
return nil, status.Errorf(codes.Internal, "%v", err)
|
|
}
|
|
}
|
|
return &proto.UploadFileRsp{
|
|
Filename: filename,
|
|
FileType: fileType,
|
|
}, nil
|
|
}
|
|
|
|
func (s *server) DownloadFile(ctx context.Context, req *proto.DownloadFileReq) (*httpbody.HttpBody, error) {
|
|
file, err := s.fileService.DownloadFile(ctx, req.Filename)
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, file_service.ErrFileNotFound):
|
|
return nil, status.Errorf(codes.NotFound, "%v", err)
|
|
default:
|
|
return nil, status.Errorf(codes.Internal, "%v", err)
|
|
}
|
|
}
|
|
// nosniff — при публичном скачивании браузер не должен угадывать
|
|
// Content-Type по содержимому (защита от stored-XSS при расхождении).
|
|
if err := grpc.SetHeader(ctx, metadata.Pairs("X-Content-Type-Options", "nosniff")); err != nil {
|
|
return nil, status.Errorf(codes.Internal, "failed to set response header: %v", err)
|
|
}
|
|
return &httpbody.HttpBody{
|
|
Data: file.Data,
|
|
ContentType: file.Mime,
|
|
}, nil
|
|
}
|