Files
phishingclub/backend/vo/file.go
2025-08-21 16:14:09 +02:00

191 lines
4.8 KiB
Go

package vo
import (
"encoding/json"
"fmt"
"path"
"strings"
"github.com/phishingclub/phishingclub/validate"
)
type FileName struct {
inner string
}
// NewFileName creates a new file name
func NewFileName(p string) (*FileName, error) {
p = strings.TrimSpace(p)
p = path.Clean(p)
// string can not start with /, ./ or ..
err := validate.ErrorIfStringNotbetweenOrEqualTo(p, 1, 255)
if err != nil {
return nil, fmt.Errorf("invalid file name: %w", err)
}
// allow only a-zA-Z0-9_-. and space
err = validate.ErrorIfStringNotMatch(p, `^[a-zA-Z0-9_\-.\s]+$`)
if err != nil {
// Find and return the illegal characters
illegalChars := ""
for _, char := range p {
if !strings.ContainsRune(`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. `, char) {
illegalChars += string(char)
}
}
return nil, fmt.Errorf("invalid file name - Allows is characters, numbers, _, -, . and space. Illegal characters: %s", illegalChars)
}
return &FileName{
inner: p,
}, nil
}
// NewFileNameMust creates a new file name and panics if it fails
func NewFileNameMust(p string) *FileName {
f, err := NewFileName(p)
if err != nil {
panic(err)
}
return f
}
// MarshalJSON implements the json.Marshaler interface
func (s FileName) MarshalJSON() ([]byte, error) {
return json.Marshal(s.inner)
}
// UnmarshalJSON unmarshals the json into a string
func (s *FileName) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
v, err := NewFileName(str)
if err != nil {
return err
}
s.inner = v.inner
return nil
}
// String returns the string representation of the file name
func (f FileName) String() string {
return f.inner
}
type RelativeFilePath struct {
inner string
}
// NewRelativeFilePath creates a new file path
func NewRelativeFilePath(p string) (*RelativeFilePath, error) {
p = strings.TrimSpace(p)
p = path.Clean(p)
// string can not start with /, ./ or ..
err := validate.ErrorIfStringNotbetweenOrEqualTo(p, 1, 512)
if err != nil {
return nil, fmt.Errorf("invalid path: %w", err)
}
// allow only a-zA-Z0-9_-. and / and space
err = validate.ErrorIfStringNotMatch(p, `^[a-zA-Z0-9_\-./\s]+$`)
if err != nil {
// Find and return the illegal characters
illegalChars := ""
for _, char := range p {
if !strings.ContainsRune(`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-. /`, char) {
illegalChars += string(char)
}
}
return nil, fmt.Errorf("Invalid path. Invalid characters: %s", illegalChars)
}
return &RelativeFilePath{
inner: p,
}, nil
}
// NewRelativeFilePathMust creates a new file path and panics if it fails
func NewRelativeFilePathMust(p string) *RelativeFilePath {
f, err := NewRelativeFilePath(p)
if err != nil {
panic(err)
}
return f
}
// MarshalJSON implements the json.Marshaler interface
func (s RelativeFilePath) MarshalJSON() ([]byte, error) {
return json.Marshal(s.inner)
}
// UnmarshalJSON unmarshals the json into a string
func (s *RelativeFilePath) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
v, err := NewRelativeFilePath(str)
if err != nil {
return err
}
s.inner = v.inner
return nil
}
// String returns the string representation of the file path
func (f RelativeFilePath) String() string {
return f.inner
}
type OptionalRelativePath struct {
inner string
}
// NewOptionalRelativePath creates a new optional file path that is realive
// from another folder. We make this shorter than the full path to avoid that
// the path in full path is longer than its limits, as this path is used in
// the full path along with its parent folders.
func NewOptionalRelativePath(p string) (*OptionalRelativePath, error) {
p = strings.TrimSpace(p)
p = path.Clean(p)
if len(p) > 0 {
err := validate.ErrorIfStringNotbetweenOrEqualTo(p, 1, 255)
if err != nil {
return nil, fmt.Errorf("invalid file path: %w", err)
}
// allow only a-zA-Z0-9_-. and /
err = validate.ErrorIfStringNotMatch(p, `^[a-zA-Z0-9_\-./]+$`)
if err != nil {
_ = err
return nil, fmt.Errorf("invalid path - Allows is characters, numbers and _, -, . and /")
}
}
return &OptionalRelativePath{
inner: p,
}, nil
}
// MarshalJSON implements the json.Marshaler interface
func (s OptionalRelativePath) MarshalJSON() ([]byte, error) {
return json.Marshal(s.inner)
}
// UnmarshalJSON unmarshals the json into a string
func (s *OptionalRelativePath) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
v, err := NewOptionalRelativePath(str)
if err != nil {
return err
}
s.inner = v.inner
return nil
}
// String returns the string representation of the optional file path
func (o OptionalRelativePath) String() string {
return o.inner
}