diff --git a/src/client/utils/files.go b/src/client/utils/files.go new file mode 100644 index 0000000000000000000000000000000000000000..0f0f7fd6488c2bacc319f0143262084455e157d0 --- /dev/null +++ b/src/client/utils/files.go @@ -0,0 +1,84 @@ +package utils + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "errors" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/google/uuid" +) + +// Creates a tar.gz archive of dir and all its files and subdirectories. +// Note: dir can also be a file. +// Source code slightly modified from: https://gist.github.com/mimoo/25fc9716e0f1353791f5908f94d6e726 +func TarGzDir(dir, archive string) error { + _, err := os.Stat(dir) + if errors.Is(err, fs.ErrNotExist) { + return errors.New("Error: \"" + dir + "\" does not exist") + } + + var buf bytes.Buffer + + gzWriter := gzip.NewWriter(&buf) + tarWriter := tar.NewWriter(gzWriter) + + // Walks through every file in the directory + filepath.Walk(dir, func(file string, fi os.FileInfo, err error) error { + header, err := tar.FileInfoHeader(fi, file) + if err != nil { + return err + } + + fileRel := strings.TrimPrefix(file, dir) + fileRel = filepath.Join(filepath.Base(dir), fileRel) + header.Name = filepath.ToSlash(fileRel) + + if err := tarWriter.WriteHeader(header); err != nil { + return err + } + // if not a dir, write file content + if !fi.IsDir() { + data, err := os.Open(file) + if err != nil { + return err + } + if _, err := io.Copy(tarWriter, data); err != nil { + return err + } + } + return nil + }) + + if err := tarWriter.Close(); err != nil { + return err + } + if err := gzWriter.Close(); err != nil { + return err + } + + fileToWrite, err := os.OpenFile(archive, os.O_CREATE|os.O_RDWR, os.FileMode(0750)) + if err != nil { + return err + } + if _, err := io.Copy(fileToWrite, &buf); err != nil { + return err + } + + return nil +} + +func GetRandomTempFilename() (string, error) { + tempDir := os.TempDir() + uuid, err := uuid.NewRandom() + if err != nil { + return "", errors.New("Failed creating random UUID: " + err.Error()) + } + randName := "temp_" + uuid.String() + return filepath.Join(tempDir, randName), nil +} diff --git a/src/client/utils/strings.go b/src/client/utils/strings.go new file mode 100644 index 0000000000000000000000000000000000000000..854d18605f4623c605c13acbae4628db587f24a8 --- /dev/null +++ b/src/client/utils/strings.go @@ -0,0 +1,48 @@ +package utils + +import ( + "fmt" + "io/ioutil" + "net/mail" + "strings" +) + +func IsEmail(email string) bool { + _, err := mail.ParseAddress(email) + return err == nil +} + +// Convert a string of USB devices of the form "1fc9:001d,067b:2303" +// into a slice of string where each element is a string of the form "1fc9:001d". +// Returns an empty slice if the input string is "none". +func Str2UsbDevices(s string) []string { + usbDevs := []string{} + if s != "none" { + devs := strings.Split(s, ",") // Extracts USB devices + for _, dev := range devs { + usbDevs = append(usbDevs, dev) + } + } + return usbDevs +} + +// Returns the content of file as a string +func FileToString(file string) (string, error) { + content, err := ioutil.ReadFile(file) + if err != nil { + return "", err + } + return string(content), nil +} + +// Removes an element from a string array at a given index +func RemoveArgAtIndex(slice []string, index int) []string { + return append(slice[:index], slice[index+1:]...) +} + +// TODO: better way of appending a portable "new line" to a string +func AppendNewLine(s string) string { + var newLine string + newLine = fmt.Sprintln(newLine, "") + return s + newLine +} diff --git a/src/common/utils/files.go b/src/common/utils/files.go new file mode 100644 index 0000000000000000000000000000000000000000..729503afc05dc11609c0eb56374d0095a4e16865 --- /dev/null +++ b/src/common/utils/files.go @@ -0,0 +1,12 @@ +package utils + +import ( + "errors" + "os" +) + +// Returns true if the specified file exists, false otherwise. +func FileExists(filename string) bool { + _, err := os.Stat(filename) + return !errors.Is(err, os.ErrNotExist) +} diff --git a/src/server/utils/files.go b/src/server/utils/files.go new file mode 100644 index 0000000000000000000000000000000000000000..67351766868bc956970d6ff447e3ecdcefe1615a --- /dev/null +++ b/src/server/utils/files.go @@ -0,0 +1,52 @@ +package utils + +import ( + "io" + "os" + "path/filepath" +) + +// Returns the list of subdirectories present in dir. +func GetSubDirs(dir string) ([]string, error) { + subDirs := []string{} + + currentDir, err := os.Open(dir) + if err != nil { + return nil, err + } + + // Retrieves all files entries in the directory (0 = all files in the directory). + files, err := currentDir.Readdir(0) + if err != nil { + currentDir.Close() + return nil, err + } + + currentDir.Close() + + // Loop over file entries + for _, f := range files { + if f.IsDir() { + subDirs = append(subDirs, filepath.Join(dir, f.Name())) + } + } + + return subDirs, nil +} + +func CopyFiles(source, dest string) error { + src, err := os.Open(source) + if err != nil { + return err + } + defer src.Close() + + dst, err := os.Create(dest) + if err != nil { + return err + } + defer dst.Close() + _, err = io.Copy(dst, src) + + return err +} diff --git a/src/server/utils/network.go b/src/server/utils/network.go new file mode 100644 index 0000000000000000000000000000000000000000..b0164d9c2cbf0e11619ee4dc5f95c8a7212c7d84 --- /dev/null +++ b/src/server/utils/network.go @@ -0,0 +1,35 @@ +package utils + +import ( + "math/rand" + "net" + "strconv" +) + +// Returns a random MAC address as a string (e.g. "b3:30:49:f8:d0:4b"). +func RandMacAddress() (string, error) { + buf := make([]byte, 6) + _, err := rand.Read(buf) + if err != nil { + return "", err + } + + // Sets unicast mode (bit 0 to 0) and locally administered addresses (bit 1 to 1) + // For more details, see: https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit) + buf[0] &= 0xFE + buf[0] |= 2 + + var mac net.HardwareAddr + mac = append(mac, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]) + return mac.String(), nil +} + +// Returns true if the specified TCP port is available, false otherwise. +func IsPortAvailable(port int) bool { + ln, err := net.Listen("tcp", ":"+strconv.Itoa(port)) + if err != nil { + return false + } + ln.Close() + return true +} diff --git a/src/server/utils/password.go b/src/server/utils/password.go index fdf7655c8d2e1824892023ccc0f4b25db72b69b2..90c6dabfd37e398dccb7c4b1eb7b0b51ce91c5ab 100644 --- a/src/server/utils/password.go +++ b/src/server/utils/password.go @@ -2,6 +2,7 @@ package utils import ( "github.com/sethvargo/go-password/password" + "golang.org/x/crypto/bcrypt" ) // Custom password generator with the following characters removed: 0, O, l, I @@ -10,3 +11,10 @@ var CustomPwd, _ = password.NewGenerator(&password.GeneratorInput{ UpperLetters: "ABCDEFGHJKLMNPQRSTUVWXYZ", Digits: "123456789", }) + +// Returns a hash of the "clear" password passed in argument. +func HashPassword(pwd string) string { + // Uses bcrypt to hash the password. + hashedPwd, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) + return string(hashedPwd) +} diff --git a/src/server/utils/random.go b/src/server/utils/random.go new file mode 100644 index 0000000000000000000000000000000000000000..85942a09844daeace7a5019312dd742533547e99 --- /dev/null +++ b/src/server/utils/random.go @@ -0,0 +1,16 @@ +package utils + +import ( + "math/rand" + "time" +) + +// Initializes the random number generator. +func RandInit() { + rand.Seed(time.Now().UnixNano()) +} + +// Returns an int in the range [min,max] (both inclusive). +func Rand(min, max int) int { + return rand.Intn(max-min+1) + min +}