Windows assets, check hash while upload

This commit is contained in:
Aurélie Delhaie
2022-06-16 22:45:24 +02:00
parent 5ed0cfa837
commit 86b0924148
17 changed files with 277 additions and 37 deletions

View File

@@ -1,6 +1,6 @@
#!/bin/bash
platforms=("windows/amd64" "windows/arm64" "darwin/amd64" "darwin/arm64" "linux/amd64" "linux/arm64")
platforms=("windows/amd64" "linux/amd64" "linux/arm64" "linux/arm")
if [[ -d "./build" ]]
then
@@ -8,7 +8,6 @@ then
fi
mkdir build
cd build
for platform in "${platforms[@]}"
do
@@ -16,9 +15,21 @@ do
platform_split=(${platform//\// })
GOOS=${platform_split[0]}
GOARCH=${platform_split[1]}
output_name='osc-'$GOOS'-'$GOARCH
output_name='./build/osc-'$GOOS'-'$GOARCH
if [ $GOOS = "windows" ]; then
output_name+='.exe'
go generate
env GOAMD64=v3 GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=1 go build -o $output_name -a
else
if [ $GOARCH = "arm" ]; then
env GOARM=7 GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0 go build -o $output_name -a
else
if [ $GOARCH = "amd64" ]; then
env GOAMD64=v3 GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0 go build -o $output_name -a
else
env GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0 go build -o $output_name -a
fi
env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name -a ../main.go
fi
fi
done

26
common.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
"io"
"log"
"opensavecloudserver/config"
"opensavecloudserver/database"
"os"
)
func InitCommon() {
f, err := os.OpenFile("server.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer func(f *os.File) {
err := f.Close()
if err != nil {
log.Println(err)
}
}(f)
log.SetOutput(io.MultiWriter(os.Stdout, f))
config.Init()
database.Init()
}

View File

@@ -38,7 +38,7 @@ type FeaturesConfiguration struct {
var currentConfig *Configuration
func init() {
func Init() {
path := flag.String("config", "./config.yml", "Set the configuration file path")
flag.Parse()
configYamlContent, err := os.ReadFile(*path)

View File

@@ -18,7 +18,7 @@ var db *gorm.DB
const AdminRole string = "admin"
const UserRole string = "user"
func init() {
func Init() {
dbConfig := config.Database()
var err error
connectionString := ""

10
go.mod
View File

@@ -3,6 +3,7 @@ module opensavecloudserver
go 1.18
require (
github.com/getlantern/systray v1.2.1
github.com/go-chi/chi/v5 v5.0.7
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.3.0
@@ -13,7 +14,16 @@ require (
)
require (
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.4 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
)

28
go.sum
View File

@@ -1,7 +1,25 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/systray v1.2.1 h1:udsC2k98v2hN359VTFShuQW6GGprRprw6kD6539JikI=
github.com/getlantern/systray v1.2.1/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -10,8 +28,18 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=

View File

@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
package main
import (
@@ -9,5 +12,6 @@ import (
func main() {
fmt.Printf("Open Save Cloud (Server) %s (%s %s)\n", constant.Version, runtime.GOOS, runtime.GOARCH)
InitCommon()
server.Serve()
}

47
main_windows.go Normal file
View File

@@ -0,0 +1,47 @@
//go:build windows
package main
import (
_ "embed"
"github.com/getlantern/systray"
"opensavecloudserver/constant"
"opensavecloudserver/server"
"os"
)
//go:generate go-winres make
//go:embed tray.ico
var icon []byte
func main() {
go func() {
InitCommon()
server.Serve()
}()
systray.Run(onReady, onExit)
}
func onReady() {
systray.SetIcon(icon)
systray.SetTitle("Open Save Cloud Server")
systray.SetTooltip("Open Save Cloud Server")
systray.AddMenuItem("Open Save Cloud", "").Disable()
systray.AddMenuItem(constant.Version, "").Disable()
systray.AddSeparator()
mQuit := systray.AddMenuItem("Quit", "Quit the server")
select {
case <-mQuit.ClickedCh:
quit()
}
}
func quit() {
systray.Quit()
os.Exit(0)
}
func onExit() {
systray.Quit()
}

View File

@@ -13,6 +13,7 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"time"
"unicode/utf8"
)
@@ -154,6 +155,11 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
badRequest("The header X-Game-Save-Hash is missing", w, r)
return
}
archiveHash := strings.ToLower(r.Header.Get("X-Hash"))
if utf8.RuneCountInString(hash) == 0 {
badRequest("The header X-Hash is missing", w, r)
return
}
game, err := database.GameInfoById(userId, gameId)
if err != nil {
internalServerError(w, r)
@@ -172,7 +178,13 @@ func UploadSave(w http.ResponseWriter, r *http.Request) {
log.Println(err)
}
}(file)
err = upload.ProcessFile(file, game)
err = upload.UploadToCache(file, game)
if err != nil {
internalServerError(w, r)
log.Println(err)
return
}
err = upload.ValidateAndMove(game, archiveHash)
if err != nil {
internalServerError(w, r)
log.Println(err)
@@ -216,6 +228,12 @@ func Download(w http.ResponseWriter, r *http.Request) {
savePath := filepath.Join(config.Path().Storage, strconv.Itoa(userId), game.PathStorage)
if _, err := os.Stat(savePath); err == nil {
hash, err := upload.FileHash(savePath)
if err != nil {
internalServerError(w, r)
log.Println(err)
return
}
file, err := os.Open(savePath)
if err != nil {
internalServerError(w, r)
@@ -228,6 +246,7 @@ func Download(w http.ResponseWriter, r *http.Request) {
log.Println(err)
}
}(file)
w.Header().Add("X-Hash", strings.ToUpper(hash))
_, err = io.Copy(w, file)
if err != nil {
internalServerError(w, r)

View File

@@ -36,35 +36,35 @@ func Serve() {
r.Route("/system", func(systemRouter chi.Router) {
systemRouter.Get("/information", Information)
})
r.Route("/user", func(secureRouter chi.Router) {
secureRouter.Use(authMiddleware)
secureRouter.Get("/information", UserInformation)
secureRouter.Post("/passwd", ChangePassword)
r.Route("/admin", func(adminRouter chi.Router) {
adminRouter.Use(adminMiddleware)
adminRouter.Post("/user", AddUser)
adminRouter.Post("/user/passwd/{id}", ChangeUserPassword)
adminRouter.Delete("/user/{id}", RemoveUser)
adminRouter.Get("/user/{id}", User)
adminRouter.Get("/users", AllUsers)
adminRouter.Get("/user/role/admin/{id}", SetAdmin)
adminRouter.Get("/user/role/user/{id}", SetNotAdmin)
})
r.Route("/admin", func(secureRouter chi.Router) {
secureRouter.Use(adminMiddleware)
secureRouter.Post("/user", AddUser)
secureRouter.Post("/user/passwd/{id}", ChangeUserPassword)
secureRouter.Delete("/user/{id}", RemoveUser)
secureRouter.Get("/user/{id}", User)
secureRouter.Get("/users", AllUsers)
secureRouter.Get("/user/role/admin/{id}", SetAdmin)
secureRouter.Get("/user/role/user/{id}", SetNotAdmin)
})
r.Route("/game", func(secureRouter chi.Router) {
r.Group(func(secureRouter chi.Router) {
secureRouter.Use(authMiddleware)
secureRouter.Post("/create", CreateGame)
secureRouter.Get("/all", AllGamesInformation)
secureRouter.Delete("/remove/{id}", RemoveGame)
secureRouter.Get("/info/{id}", GameInfoByID)
secureRouter.Post("/upload/init", AskForUpload)
secureRouter.Group(func(uploadRouter chi.Router) {
secureRouter.Route("/user", func(userRouter chi.Router) {
userRouter.Get("/information", UserInformation)
userRouter.Post("/passwd", ChangePassword)
})
secureRouter.Route("/game", func(gameRouter chi.Router) {
gameRouter.Post("/create", CreateGame)
gameRouter.Get("/all", AllGamesInformation)
gameRouter.Delete("/remove/{id}", RemoveGame)
gameRouter.Get("/info/{id}", GameInfoByID)
gameRouter.Post("/upload/init", AskForUpload)
gameRouter.Group(func(uploadRouter chi.Router) {
uploadRouter.Use(uploadMiddleware)
uploadRouter.Post("/upload", UploadSave)
uploadRouter.Get("/download", Download)
})
})
})
})
})
log.Println("Server is listening...")

View File

@@ -1,6 +1,7 @@
package upload
import (
"crypto/sha512"
"errors"
"fmt"
"github.com/google/uuid"
@@ -107,7 +108,7 @@ func CheckUploadToken(uploadToken string) (int, bool) {
return -1, false
}
func ProcessFile(file multipart.File, game *database.Game) error {
func UploadToCache(file multipart.File, game *database.Game) error {
filePath := path.Join(config.Path().Cache, strconv.Itoa(game.UserId))
if _, err := os.Stat(filePath); err != nil {
err = os.Mkdir(filePath, 0766)
@@ -126,13 +127,30 @@ func ProcessFile(file multipart.File, game *database.Game) error {
log.Println(err)
}
}(f)
_, err = io.Copy(f, file)
if _, err := io.Copy(f, file); err != nil {
return err
}
return nil
}
func ValidateAndMove(game *database.Game, hash string) error {
filePath := path.Join(config.Path().Cache, strconv.Itoa(game.UserId), game.PathStorage)
if err := checkHash(filePath, hash); err != nil {
return err
}
if err := moveToStorage(filePath, game); err != nil {
return err
}
return nil
}
func checkHash(path, hash string) error {
h, err := FileHash(path)
if err != nil {
return err
}
err = moveToStorage(filePath, game)
if err != nil {
return err
if h != hash {
return errors.New("hash is different")
}
return nil
}
@@ -187,6 +205,24 @@ func RemoveGame(userId int, game *database.Game) error {
return os.Remove(filePath)
}
func FileHash(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer func(f *os.File) {
err := f.Close()
if err != nil {
log.Println(err)
}
}(f)
h := sha512.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
// clearLocks clear lock of zombi upload
func clearLocks() {
mu.Lock()

BIN
winres/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
winres/icon_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
winres/icon_32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
winres/icon_48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
winres/icon_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

59
winres/winres.json Normal file
View File

@@ -0,0 +1,59 @@
{
"RT_GROUP_ICON": {
"APP": {
"0000": [
"icon_64.png",
"icon_48.png",
"icon_32.png",
"icon_16.png"
]
},
"OTHER": {
"0000": "icon.png"
}
},
"RT_MANIFEST": {
"#1": {
"0409": {
"identity": {
"name": "Open Save Cloud Server",
"version": "1.0.0.0"
},
"description": "",
"minimum-os": "win7",
"execution-level": "as invoker",
"ui-access": false,
"auto-elevate": false,
"dpi-awareness": "per monitor v2",
"disable-theming": false,
"disable-window-filtering": false,
"high-resolution-scrolling-aware": false,
"ultra-high-resolution-scrolling-aware": false,
"long-path-aware": false,
"printer-driver-isolation": false,
"gdi-scaling": false,
"segment-heap": false,
"use-common-controls-v6": false
}
}
},
"RT_VERSION": {
"#1": {
"0000": {
"fixed": {
"file_version": "1.0.0.0",
"product_version": "1.0.0.0"
},
"info": {
"0409": {
"CompanyName": "Aurelie Delhaie",
"FileDescription": "The server of Open Save Cloud",
"FileVersion": "1.0.0.0",
"ProductName": "Open Save Cloud Server",
"ProductVersion": "1.0.0.0"
}
}
}
}
}
}