first commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
config.yml
|
||||
cache/
|
||||
opensavecloudserver
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
.idea/misc.xml
generated
Normal file
8
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SwUserDefinedSpecifications">
|
||||
<option name="specTypeByUrl">
|
||||
<map />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/opensavecloudserver.iml" filepath="$PROJECT_DIR$/.idea/opensavecloudserver.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/opensavecloudserver.iml
generated
Normal file
9
.idea/opensavecloudserver.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
84
authentication/authentication.go
Normal file
84
authentication/authentication.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package authentication
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"log"
|
||||
"opensavecloudserver/database"
|
||||
"time"
|
||||
)
|
||||
|
||||
var secret []byte
|
||||
|
||||
type AccessToken struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type Registration struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Pronouns int `json:"pronouns"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
secret = make([]byte, 512)
|
||||
_, err := rand.Read(secret)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Connect(username, password string) (*AccessToken, error) {
|
||||
user, err := database.UserByUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(password)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token, err := token(user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &AccessToken{
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ParseToken(token string) (int, error) {
|
||||
var claims jwt.MapClaims
|
||||
_, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return secret, nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if userId, ok := claims["sub"]; ok {
|
||||
return int(userId.(float64)), nil
|
||||
}
|
||||
return 0, errors.New("this token does not have a userId in it")
|
||||
}
|
||||
|
||||
func Register(user *Registration) error {
|
||||
_, err := database.UserByUsername(user.Username)
|
||||
if err == nil {
|
||||
return errors.New("this username already exist")
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.AddUser(user.Username, user.Firstname, user.Lastname, hash, user.Pronouns)
|
||||
}
|
||||
|
||||
func token(userId int) (string, error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{
|
||||
"sub": userId,
|
||||
"exp": time.Now().Add(1 * time.Hour).Unix(),
|
||||
})
|
||||
return token.SignedString(secret)
|
||||
}
|
||||
9
config.default.yml
Normal file
9
config.default.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
database:
|
||||
host: localhost
|
||||
password: root
|
||||
port: 3306
|
||||
username: root
|
||||
features:
|
||||
allow_register: false
|
||||
cache: "/var/osc/cache"
|
||||
52
config/config.go
Normal file
52
config/config.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"gopkg.in/yaml.v3"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
Database DatabaseConfiguration `yaml:"database"`
|
||||
Features FeaturesConfiguration `yaml:"features"`
|
||||
Cache string `yaml:"cache"`
|
||||
}
|
||||
|
||||
type DatabaseConfiguration struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
type FeaturesConfiguration struct {
|
||||
AllowRegister bool `yaml:"allow_register"`
|
||||
}
|
||||
|
||||
var currentConfig *Configuration
|
||||
|
||||
func init() {
|
||||
path := flag.String("config", "./config.yml", "Set the configuration file path")
|
||||
flag.Parse()
|
||||
configYamlContent, err := os.ReadFile(*path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = yaml.Unmarshal(configYamlContent, ¤tConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Database() *DatabaseConfiguration {
|
||||
return ¤tConfig.Database
|
||||
}
|
||||
|
||||
func Features() *FeaturesConfiguration {
|
||||
return ¤tConfig.Features
|
||||
}
|
||||
|
||||
func Cache() string {
|
||||
return currentConfig.Cache
|
||||
}
|
||||
5
constant/constant.go
Normal file
5
constant/constant.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package constant
|
||||
|
||||
const Version = "1.0.0"
|
||||
|
||||
const ApiVersion = 1
|
||||
83
database/database.go
Normal file
83
database/database.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"opensavecloudserver/config"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func init() {
|
||||
dbConfig := config.Database()
|
||||
var err error
|
||||
db, err = gorm.Open(mysql.Open(
|
||||
fmt.Sprintf("%s:%s@tcp(%s:%d)/transagenda?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
dbConfig.Username,
|
||||
dbConfig.Password,
|
||||
dbConfig.Host,
|
||||
dbConfig.Port),
|
||||
), &gorm.Config{
|
||||
Logger: logger.New(
|
||||
log.New(os.Stdout, "", log.LstdFlags), // io writer
|
||||
logger.Config{
|
||||
SlowThreshold: time.Second, // Slow SQL threshold
|
||||
LogLevel: logger.Error, // Log level
|
||||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
||||
Colorful: true, // Enable color
|
||||
},
|
||||
),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func UserByUsername(username string) (*User, error) {
|
||||
var user *User
|
||||
err := db.Model(User{}).Where(User{Username: username}).First(&user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func UserById(userId int) (*User, error) {
|
||||
var user *User
|
||||
err := db.Model(User{}).Where(User{ID: userId}).First(&user).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func AddUser(username string, password []byte) error {
|
||||
user := &User{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
return db.Save(user).Error
|
||||
}
|
||||
|
||||
func GameInfoById(userId, gameId int) (*Game, error) {
|
||||
var game *Game
|
||||
err := db.Model(Game{}).Where(Game{ID: gameId, UserId: userId}).First(&game).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return game, nil
|
||||
}
|
||||
|
||||
func GameInfosByUserId(userId int) ([]*Game, error) {
|
||||
var games []*Game
|
||||
err := db.Model(Game{}).Where(Game{UserId: userId}).Find(&games).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return games, nil
|
||||
}
|
||||
20
database/model.go
Normal file
20
database/model.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package database
|
||||
|
||||
import "time"
|
||||
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password []byte `json:"-"`
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Revision int `json:"rev"`
|
||||
PathStorage string `json:"-"`
|
||||
Hash string `json:"hash"`
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
UserId int `json:"-"`
|
||||
Available bool `json:"available"`
|
||||
}
|
||||
18
go.mod
Normal file
18
go.mod
Normal file
@@ -0,0 +1,18 @@
|
||||
module opensavecloudserver
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gorm.io/driver/mysql v1.3.3
|
||||
gorm.io/gorm v1.23.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.4 // indirect
|
||||
)
|
||||
21
go.sum
Normal file
21
go.sum
Normal file
@@ -0,0 +1,21 @@
|
||||
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/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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
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=
|
||||
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=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.3.3 h1:jXG9ANrwBc4+bMvBcSl8zCfPBaVoPyBEBshA8dA93X8=
|
||||
gorm.io/driver/mysql v1.3.3/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
|
||||
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
|
||||
gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
13
main.go
Normal file
13
main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"opensavecloudserver/constant"
|
||||
"opensavecloudserver/server"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Open Save Cloud (Server) %s (%s %s)\n", constant.Version, runtime.GOOS, runtime.GOARCH)
|
||||
server.Serve()
|
||||
}
|
||||
64
server/authentication.go
Normal file
64
server/authentication.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"opensavecloudserver/authentication"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Credential struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func Login(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
credential := new(Credential)
|
||||
err = json.Unmarshal(body, credential)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
token, err := authentication.Connect(credential.Username, credential.Password)
|
||||
if err != nil {
|
||||
unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
ok(token, w, r)
|
||||
}
|
||||
|
||||
func Register(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
registration := new(authentication.Registration)
|
||||
err = json.Unmarshal(body, registration)
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
err = authentication.Register(registration)
|
||||
if err != nil {
|
||||
badRequest(err.Error(), w, r)
|
||||
return
|
||||
}
|
||||
payload := successMessage{
|
||||
Message: "You are now registered",
|
||||
Timestamp: time.Now(),
|
||||
Status: 200,
|
||||
}
|
||||
ok(payload, w, r)
|
||||
}
|
||||
1
server/data.go
Normal file
1
server/data.go
Normal file
@@ -0,0 +1 @@
|
||||
package server
|
||||
98
server/response.go
Normal file
98
server/response.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type httpError struct {
|
||||
Status int `json:"status"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Error string `json:"error"`
|
||||
Message string `json:"message"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type successMessage struct {
|
||||
Status int `json:"status"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func internalServerError(w http.ResponseWriter, r *http.Request) {
|
||||
e := httpError{
|
||||
Status: 500,
|
||||
Error: "Internal Server Error",
|
||||
Message: "The server encountered an unexpected condition that prevented it from fulfilling the request.",
|
||||
Path: r.RequestURI,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(500)
|
||||
_, err = w.Write(payload)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func unauthorized(w http.ResponseWriter, r *http.Request) {
|
||||
e := httpError{
|
||||
Status: 401,
|
||||
Error: "Unauthorized",
|
||||
Message: "The request has not been completed because it lacks valid authentication credentials for the requested resource.",
|
||||
Path: r.RequestURI,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.Header().Add("WWW-Authenticate", "Custom realm=\"Login via /api/login\"")
|
||||
w.WriteHeader(401)
|
||||
_, err = w.Write(payload)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ok(obj interface{}, w http.ResponseWriter, _ *http.Request) {
|
||||
payload, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
_, err = w.Write(payload)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func badRequest(message string, w http.ResponseWriter, r *http.Request) {
|
||||
e := httpError{
|
||||
Status: 400,
|
||||
Error: "Bad Request",
|
||||
Message: message,
|
||||
Path: r.RequestURI,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
_, err = w.Write(payload)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
78
server/server.go
Normal file
78
server/server.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"log"
|
||||
"net/http"
|
||||
"opensavecloudserver/authentication"
|
||||
"opensavecloudserver/config"
|
||||
)
|
||||
|
||||
type ContextKey string
|
||||
|
||||
const UserIdKey ContextKey = "userId"
|
||||
|
||||
// Serve start the http server
|
||||
func Serve() {
|
||||
router := chi.NewRouter()
|
||||
router.Use(middleware.Logger)
|
||||
router.Use(recovery)
|
||||
router.Route("/api", func(r chi.Router) {
|
||||
r.Post("/login", Login)
|
||||
if config.Features().AllowRegister {
|
||||
r.Post("/register", Register)
|
||||
}
|
||||
r.Route("/system", func(systemRouter chi.Router) {
|
||||
systemRouter.Get("/information", Information)
|
||||
})
|
||||
r.Group(func(secureRouter chi.Router) {
|
||||
secureRouter.Use(authMiddleware)
|
||||
})
|
||||
})
|
||||
log.Println("Server is listening...")
|
||||
err := http.ListenAndServe(":8080", router)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// authMiddleware filter the request
|
||||
func authMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
header := r.Header.Get("Authorization")
|
||||
if len(header) > 7 {
|
||||
userId, err := authentication.ParseToken(header[7:])
|
||||
if err != nil {
|
||||
unauthorized(w, r)
|
||||
return
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), UserIdKey, userId)
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
unauthorized(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func userIdFromContext(ctx context.Context) (int, error) {
|
||||
if userId, ok := ctx.Value(UserIdKey).(int); ok {
|
||||
return userId, nil
|
||||
}
|
||||
return 0, errors.New("userId not found in context")
|
||||
}
|
||||
|
||||
func recovery(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
internalServerError(w, r)
|
||||
}
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
29
server/system.go
Normal file
29
server/system.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"opensavecloudserver/config"
|
||||
"opensavecloudserver/constant"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type information struct {
|
||||
AllowRegister bool `json:"allow_register"`
|
||||
Version string `json:"version"`
|
||||
ApiVersion int `json:"api_version"`
|
||||
GoVersion string `json:"go_version"`
|
||||
OsName string `json:"os_name"`
|
||||
OsArchitecture string `json:"os_architecture"`
|
||||
}
|
||||
|
||||
func Information(w http.ResponseWriter, r *http.Request) {
|
||||
info := information{
|
||||
AllowRegister: config.Features().AllowRegister,
|
||||
Version: constant.Version,
|
||||
ApiVersion: constant.ApiVersion,
|
||||
GoVersion: runtime.Version(),
|
||||
OsName: runtime.GOOS,
|
||||
OsArchitecture: runtime.GOARCH,
|
||||
}
|
||||
ok(info, w, r)
|
||||
}
|
||||
Reference in New Issue
Block a user