From f04423c82cbf4422ba2bc0b4f6c7f94a123dcd8a Mon Sep 17 00:00:00 2001 From: Nicolas Choquet Date: Fri, 22 Mar 2024 22:00:16 +0100 Subject: [PATCH] - Add Oauth authentication - Add internal Swagger UI - Add cors --- .github/workflows/build.yml | 0 .gitignore | 0 README.md | 5 + actions/main.go | 22 +- arrays/main.go | 16 + auth/checkToken.go | 65 -- auth/credentials/createNewToken.go | 19 + auth/credentials/generateClientId.go | 7 + auth/credentials/generateClientSecret.go | 7 + auth/credentials/generateCredentials.go | 48 + auth/credentials/main.go | 3 + auth/credentials/updateCredentials.go | 40 + auth/generateSignatureToken.go | 69 -- auth/generateToken.go | 10 - auth/getToken.go | 156 ---- auth/main.go | 107 ++- auth/refreshToken.go | 168 ---- auth/roles/Role.go | 51 ++ auth/roles/getUserRole.go | 54 ++ auth/roles/showRoles.go | 63 ++ auth/tokens/checkToken.go | 98 ++ auth/tokens/generateToken.go | 9 + auth/tokens/getToken.go | 171 ++++ auth/tokens/refreshToken.go | 153 ++++ checkValidity.go | 3 +- consoleColors/main_darwin.go | 11 + consoleColors/main_linux.go | 11 + consoleColors/main_windows.go | 11 + customFs/directory.go | 0 customFs/file.go | 0 customFs/helpers.go | 0 customFs/main_darwin.go | 0 customFs/main_linux.go | 0 customFs/main_windows.go | 0 customHttp/acceptOptions.go | 7 + customHttp/cors.go | 29 + customHttp/error.go | 16 + customHttp/getAddr.go | 0 customHttp/getUserIp.go | 0 data/main.go | 42 - database/main.go | 116 +++ directories/createDirectory.go | 20 +- directories/deleteDirectory.go | 12 +- directories/getDirectoryItemList.go | 13 +- directories/renameDirectory.go | 20 +- files/createFile.go | 27 +- files/deleteFile.go | 12 +- files/formats.go | 0 files/getFileContent.go | 20 +- files/updateFile.go | 35 +- flags/flags.go | 35 +- flags/getFlags.go | 15 +- go.mod | 44 +- go.sum | 172 ++++ integer/random.go | 7 + main.go | 39 +- swagger/definition.go | 49 + swagger/docs.go | 36 + swagger/swagger.json | 866 ++++++++++++++++++ .../swagger.yaml | 158 ++-- types/checkValidity.go | 0 types/httpError.go | 0 types/responseStatus.go | 0 63 files changed, 2428 insertions(+), 739 deletions(-) mode change 100644 => 100755 .github/workflows/build.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 README.md mode change 100644 => 100755 actions/main.go mode change 100644 => 100755 arrays/main.go delete mode 100644 auth/checkToken.go create mode 100755 auth/credentials/createNewToken.go create mode 100755 auth/credentials/generateClientId.go create mode 100755 auth/credentials/generateClientSecret.go create mode 100755 auth/credentials/generateCredentials.go create mode 100755 auth/credentials/main.go create mode 100755 auth/credentials/updateCredentials.go delete mode 100644 auth/generateSignatureToken.go delete mode 100644 auth/generateToken.go delete mode 100644 auth/getToken.go mode change 100644 => 100755 auth/main.go delete mode 100644 auth/refreshToken.go create mode 100755 auth/roles/Role.go create mode 100755 auth/roles/getUserRole.go create mode 100755 auth/roles/showRoles.go create mode 100755 auth/tokens/checkToken.go create mode 100755 auth/tokens/generateToken.go create mode 100755 auth/tokens/getToken.go create mode 100755 auth/tokens/refreshToken.go mode change 100644 => 100755 checkValidity.go create mode 100755 consoleColors/main_darwin.go create mode 100755 consoleColors/main_linux.go create mode 100755 consoleColors/main_windows.go mode change 100644 => 100755 customFs/directory.go mode change 100644 => 100755 customFs/file.go mode change 100644 => 100755 customFs/helpers.go mode change 100644 => 100755 customFs/main_darwin.go mode change 100644 => 100755 customFs/main_linux.go mode change 100644 => 100755 customFs/main_windows.go create mode 100755 customHttp/acceptOptions.go create mode 100755 customHttp/cors.go create mode 100755 customHttp/error.go mode change 100644 => 100755 customHttp/getAddr.go mode change 100644 => 100755 customHttp/getUserIp.go delete mode 100644 data/main.go create mode 100755 database/main.go mode change 100644 => 100755 directories/createDirectory.go mode change 100644 => 100755 directories/deleteDirectory.go mode change 100644 => 100755 directories/getDirectoryItemList.go mode change 100644 => 100755 directories/renameDirectory.go mode change 100644 => 100755 files/createFile.go mode change 100644 => 100755 files/deleteFile.go mode change 100644 => 100755 files/formats.go mode change 100644 => 100755 files/getFileContent.go mode change 100644 => 100755 files/updateFile.go mode change 100644 => 100755 flags/flags.go mode change 100644 => 100755 flags/getFlags.go mode change 100644 => 100755 go.mod mode change 100644 => 100755 go.sum create mode 100755 integer/random.go mode change 100644 => 100755 main.go create mode 100755 swagger/definition.go create mode 100755 swagger/docs.go create mode 100755 swagger/swagger.json rename file-system-service.swagger.yml => swagger/swagger.yaml (86%) mode change 100644 => 100755 mode change 100644 => 100755 types/checkValidity.go mode change 100644 => 100755 types/httpError.go mode change 100644 => 100755 types/responseStatus.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 1b5223d..15609c9 --- a/README.md +++ b/README.md @@ -52,6 +52,11 @@ Click on `file-system-service-windows-{version}-windows-amd64.zip` file-system-service --generate-signature ``` +## Swagger +- [Fichiers de définitions json](./swagger/swagger.json) +- [Fichiers de définitions yaml](./swagger/swagger.yaml) +- [Swagger UI accessible ici](http://localhost:3000/swagger) + ## API Reference #### Check Validity diff --git a/actions/main.go b/actions/main.go old mode 100644 new mode 100755 index a595bbf..f8cf9ff --- a/actions/main.go +++ b/actions/main.go @@ -1,15 +1,31 @@ package actions import ( - "filesystem_service/auth" + "filesystem_service/auth/credentials" + "filesystem_service/auth/roles" "filesystem_service/flags" ) func Exec() bool { fl := flags.GetFlags() - if fl.IsGenerateSignature() { - auth.GenerateSignatureTokenAction() + if fl.IsShowRoles() { + roles.ShowRoles() + return true + } + + if fl.IsUpdateCredentials() { + credentials.UpdateCredentials(fl.GetClientId(), fl.GetRole()) + return true + } + + if fl.IsShowUserRole() { + roles.GetUserRole(fl.GetClientId()) + return true + } + + if fl.IsGenerateCredentials() { + credentials.GenerateCredentials(fl.GetRole()) return true } diff --git a/arrays/main.go b/arrays/main.go old mode 100644 new mode 100755 index 052702c..d8fbb75 --- a/arrays/main.go +++ b/arrays/main.go @@ -21,3 +21,19 @@ func Filter[T any](ts []T, f func(T) bool) []T { func Generate[T any](length int) []T { return make([]T, length) } + +func Keys[T any](arr []T) (keys []int) { + for i, _ := range arr { + keys = append(keys, i) + } + return +} + +func IsIn[T comparable](v T, a []T) bool { + for _, val := range a { + if v == val { + return true + } + } + return false +} diff --git a/auth/checkToken.go b/auth/checkToken.go deleted file mode 100644 index 4d79bd8..0000000 --- a/auth/checkToken.go +++ /dev/null @@ -1,65 +0,0 @@ -package auth - -import ( - "encoding/json" - "filesystem_service/customHttp" - "filesystem_service/data" - "filesystem_service/types" - "fmt" - "net/http" - "strings" -) - -func CheckToken(request *http.Request) (bool, error) { - signature := request.Header.Get("Signature-Token") - token := strings.Replace(request.Header.Get("Authorization"), "Bearer ", "", 1) - - if token == "" || signature == "" { - return false, fmt.Errorf("you are not authorized") - } - - ip, err := customHttp.GetUserIp(request) - if err != nil { - return false, err - } - - db, err := data.InitDatabase() - defer db.Close() - if err != nil { - return false, err - } - - results, err := db.Query(fmt.Sprintf( - "SELECT * FROM tokens WHERE IP=\"%v\" AND active=TRUE AND type=\"classic\" AND token=\"%s\" AND signature=\"%s\"", - ip, token, signature, - )) - if err != nil { - return false, err - } - - tokens, err := data.ReadRows[Token](results, func(t *Token) error { - return results.Scan(&t.Id, &t.Ip, &t.Token, &t.Signature, &t.Type, &t.Active, &t.CreatedAt) - }) - if err != nil { - return false, err - } - - if len(tokens) == 0 { - return false, fmt.Errorf("invalid access token") - } - - return true, nil -} - -func IsAuthorized(writer http.ResponseWriter, request *http.Request) bool { - if _, err := CheckToken(request); err != nil { - writer.WriteHeader(403) - response, _ := json.Marshal(&types.HttpError{ - Code: 403, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return false - } - return true -} diff --git a/auth/credentials/createNewToken.go b/auth/credentials/createNewToken.go new file mode 100755 index 0000000..a62cc26 --- /dev/null +++ b/auth/credentials/createNewToken.go @@ -0,0 +1,19 @@ +package credentials + +import ( + "filesystem_service/arrays" + "filesystem_service/integer" + "strings" +) + +func CreateNewToken(availableCharacters string, charNumber int) string { + return strings.Join( + arrays.Map[string, string]( + arrays.Generate[string](charNumber), + func(t string) string { + return strings.Split(availableCharacters, "")[integer.RandomBetween(0, len(availableCharacters)-1)] + }, + ), + "", + ) +} diff --git a/auth/credentials/generateClientId.go b/auth/credentials/generateClientId.go new file mode 100755 index 0000000..845f38e --- /dev/null +++ b/auth/credentials/generateClientId.go @@ -0,0 +1,7 @@ +package credentials + +import "fmt" + +func GenerateClientId() string { + return fmt.Sprintf("fs_service_i@%v", CreateNewToken(AvailableCharacters, 15)) +} diff --git a/auth/credentials/generateClientSecret.go b/auth/credentials/generateClientSecret.go new file mode 100755 index 0000000..1ef2fcc --- /dev/null +++ b/auth/credentials/generateClientSecret.go @@ -0,0 +1,7 @@ +package credentials + +import "fmt" + +func GenerateClientSecret() string { + return fmt.Sprintf("fs_service_s@%v", CreateNewToken(AvailableCharacters, 15)) +} diff --git a/auth/credentials/generateCredentials.go b/auth/credentials/generateCredentials.go new file mode 100755 index 0000000..820b47d --- /dev/null +++ b/auth/credentials/generateCredentials.go @@ -0,0 +1,48 @@ +package credentials + +import ( + "filesystem_service/auth/roles" + "filesystem_service/database" + "fmt" +) + +func GenerateCredentials(role string) { + db, err := database.Init() + defer db.Close() + if err != nil { + fmt.Printf("Une erreur est survenue lors de l'initialisation de la base de donnée.\n") + fmt.Printf(err.Error() + "\n") + return + } + + roleId := roles.GetRoleIdFromName(db, role) + + if roleId != -1 { + fmt.Printf("Generation du client_id ...\n") + fmt.Printf("Generation du client_secret ...\n") + clientId := GenerateClientId() + clientSecret := GenerateClientSecret() + + if _, err = db.Exec(`UPDATE credentials + SET active = FALSE + WHERE active = TRUE;`); err != nil { + fmt.Printf("\nUne erreur est survenue lors de la création du token de signature.\n") + fmt.Printf(err.Error() + "\n") + return + } + + if _, err = db.Exec(`INSERT INTO credentials ( + client_id, + client_secret, + role, + active + ) VALUES (?, ?, ?, TRUE);`, clientId, clientSecret, roleId); err != nil { + fmt.Printf("\nUne erreur est survenue lors de la création du token de signature.\n") + fmt.Printf(err.Error() + "\n") + return + } + + fmt.Printf("\nVous devrez les saisir dans le système d'exploitation web.\n") + fmt.Printf("\n=> client_id: %v\n=> client_secret: %v\n", clientId, clientSecret) + } +} diff --git a/auth/credentials/main.go b/auth/credentials/main.go new file mode 100755 index 0000000..47e7ecc --- /dev/null +++ b/auth/credentials/main.go @@ -0,0 +1,3 @@ +package credentials + +var AvailableCharacters = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789" diff --git a/auth/credentials/updateCredentials.go b/auth/credentials/updateCredentials.go new file mode 100755 index 0000000..853a27d --- /dev/null +++ b/auth/credentials/updateCredentials.go @@ -0,0 +1,40 @@ +package credentials + +import ( + "filesystem_service/auth/roles" + "filesystem_service/database" + "fmt" +) + +func UpdateCredentials(clientId string, newRole string) { + if clientId == "" { + fmt.Printf("Vous devez renseigner le client_id.\n") + return + } + + if newRole == "" { + fmt.Printf("Vous devez renseigner votre nouveau rôle.\n") + return + } + + db, err := database.Init() + defer db.Close() + if err != nil { + fmt.Printf("Une erreur est survenue lors de l'initialisation de la base de donnée.\n") + fmt.Printf(err.Error() + "\n") + return + } + + newRoleId := roles.GetRoleIdFromName(db, newRole) + + if _, err = db.Exec( + `UPDATE credentials SET role = ? WHERE client_id = ?;`, + newRoleId, clientId, + ); err != nil { + fmt.Printf("Une erreur est survenue lors de laa modification de votre rôle.\n") + fmt.Printf(err.Error() + "\n") + return + } + + fmt.Printf("Votre rôle à bien été modifié.\n") +} diff --git a/auth/generateSignatureToken.go b/auth/generateSignatureToken.go deleted file mode 100644 index 344c838..0000000 --- a/auth/generateSignatureToken.go +++ /dev/null @@ -1,69 +0,0 @@ -package auth - -import ( - "filesystem_service/arrays" - "filesystem_service/data" - "fmt" - "math/rand" - "strings" - - "github.com/atotto/clipboard" -) - -func randInt(min, max int) int { - return min + rand.Intn(max-min) -} - -var availableCharacters = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789+-*/=!&@#'()|\\{}[]_~" - -func getNewToken(availableCharacters string, charNumber int) string { - return strings.Join( - arrays.Map( - arrays.Generate[string](charNumber), - func(t string) string { - return strings.Split(availableCharacters, "")[randInt(0, len(availableCharacters)-1)] - }, - ), - "", - ) -} - -func generateSignatureToken() string { - return getNewToken(availableCharacters, 60) -} - -func GenerateSignatureTokenAction() { - fmt.Printf("Generation du token de signature ...\n") - token := generateSignatureToken() - err := clipboard.WriteAll(token) - db, err := data.InitDatabase() - defer db.Close() - if err != nil { - fmt.Printf("Une erreur est survenue lors de l'initialisation de la base de donnée.\n") - fmt.Printf(err.Error() + "\n") - return - } - - _, err = db.Exec(`UPDATE signatures SET active=FALSE where active=TRUE`, token) - if err != nil { - fmt.Printf("Une erreur est survenue lors de la création du token de signature.\n") - fmt.Printf(err.Error() + "\n") - return - } - - _, err = db.Exec(`INSERT INTO signatures (signature) VALUES (?)`, token) - if err != nil { - fmt.Printf("Une erreur est survenue lors de la création du token de signature.\n") - fmt.Printf(err.Error() + "\n") - return - } - - if err != nil { - fmt.Printf("Vous devrez le saisir dans le système d'exploitation web.\n") - fmt.Printf("Nous n'avons pas pu le mettre dans votre press-papier mais le voici ci-dessous:\n") - } else { - fmt.Printf("Nous l'avons mis dans votre presse-papier.\n") - fmt.Printf("Vous devrez le saisir dans le système d'exploitation web.\n") - } - fmt.Printf("\n=> %v\n", token) -} diff --git a/auth/generateToken.go b/auth/generateToken.go deleted file mode 100644 index 8ac8391..0000000 --- a/auth/generateToken.go +++ /dev/null @@ -1,10 +0,0 @@ -package auth - -import "fmt" - -func GenerateToken(signature string) (string, error) { - if signature == "" { - return "", fmt.Errorf("signature is empty") - } - return getNewToken(signature, 60), nil -} diff --git a/auth/getToken.go b/auth/getToken.go deleted file mode 100644 index a0c245c..0000000 --- a/auth/getToken.go +++ /dev/null @@ -1,156 +0,0 @@ -package auth - -import ( - "encoding/json" - "filesystem_service/customHttp" - "filesystem_service/data" - "filesystem_service/types" - "net/http" - "time" -) - -func GetToken(writer http.ResponseWriter, request *http.Request) { - writer.Header().Set("Access-Control-Allow-Origin", "*") - writer.Header().Add("Content-Type", "application/json") - db, err := data.InitDatabase() - defer db.Close() - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - signatureToken := request.Header.Get("Signature-Token") - - if signatureToken == "" { - writer.WriteHeader(400) - response, _ := json.Marshal(types.HttpError{ - Code: 400, - Message: "You must input your signature token", - }) - _, _ = writer.Write(response) - return - } - - foundSignatures, err := db.Query( - `SELECT * FROM signatures WHERE active=TRUE AND signature=?`, - signatureToken, - ) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - signatures, err := data.ReadRows[Signature](foundSignatures, func(t *Signature) error { - return foundSignatures.Scan(&t.Id, &t.Signature, &t.Active) - }) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - if len(signatures) == 0 { - writer.WriteHeader(403) - response, _ := json.Marshal(types.HttpError{ - Code: 403, - Message: "You are not identified", - }) - _, _ = writer.Write(response) - return - } - - signature := signatures[0].Signature - token, err := GenerateToken(signature) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - refreshToken, err := GenerateToken(token) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - ip, err := customHttp.GetUserIp(request) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - _, err = db.Exec(`UPDATE tokens SET active=FALSE WHERE IP=? AND active=TRUE`, ip) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - _, err = db.Exec( - `INSERT INTO tokens (IP, token, signature, type, created_at) VALUES (?, ?, ?, ?, ?)`, - ip, token, signature, "classic", time.Now().Unix(), - ) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - _, err = db.Exec( - `INSERT INTO tokens (IP, token, signature, type, created_at) VALUES (?, ?, ?, ?, ?)`, - ip, refreshToken, signature, "refresh", time.Now().Unix(), - ) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - tokenResponse := &GetTokenResponse{ - AccessToken: token, - RefreshToken: refreshToken, - CreatedAt: time.Now().Unix(), - // 1h (en ms) - ExpiresIn: 3600000, - } - - response, _ := json.Marshal(tokenResponse) - _, _ = writer.Write(response) -} diff --git a/auth/main.go b/auth/main.go old mode 100644 new mode 100755 index 4bcbbcc..6cd40c5 --- a/auth/main.go +++ b/auth/main.go @@ -1,24 +1,105 @@ package auth -type GetTokenResponse struct { - AccessToken string `json:"access_token"` +import ( + "filesystem_service/database" + "strings" + "time" +) + +type Credential struct { + ClientId string + ClientSecret string + Role string + CreationDate string + UpdatedDate *string + ExpiresIn int + IsActive bool +} + +func (c *Credential) GetCreationDate() time.Time { + creationDate, _ := time.Parse(time.DateTime, c.CreationDate) + return creationDate +} + +func (c *Credential) GetUpdatedDate() time.Time { + if creationDate, err := time.Parse(time.DateTime, c.CreationDate); err != nil { + return c.GetCreationDate() + } else { + return creationDate + } +} + +type JsonToken struct { + ref *Token + Token string `json:"access_token"` RefreshToken string `json:"refresh_token"` CreatedAt int64 `json:"created_at"` ExpiresIn int `json:"expires_in"` } -type Signature struct { - Id int `json:"id"` - Signature string `json:"signature"` - Active bool `json:"active"` +func (t *JsonToken) ToToken() *Token { + return t.ref } type Token struct { - Id int `json:"id"` - Ip string - Token string `json:"token"` - Signature string `json:"signature"` - Type string `json:"type"` - Active bool `json:"active"` - CreatedAt int `json:"created_at"` + Id int + Ip string + ClientId string + credentials *Credential + Token string + RefreshToken string + CreatedAt string + UpdatedAt int64 + ExpiresIn int + Active bool +} + +func (t *Token) GetCreationDate() int64 { + format := time.RFC3339 + if strings.Contains(t.CreatedAt, " UTC") { + format = time.DateTime + } + creationDate, _ := time.Parse(format, t.CreatedAt) + return creationDate.Unix() +} + +func (t *Token) GetCredentials() (*Credential, error) { + if t.ClientId != "" && t.credentials == nil { + db, err := database.Init() + if err != nil { + return nil, err + } + + rows, err := db.Query(`SELECT client_id, client_secret, + role_name as role, + creation_date, updated_date, + expires_in, c.active as active + FROM credentials c INNER JOIN roles r ON r.id = c.role + WHERE c.active = TRUE AND + client_id = ?;`, t.ClientId) + if err != nil { + return nil, err + } + + credentials, err := database.ReadRows[Credential](rows, func(c *Credential) error { + return rows.Scan(&c.ClientId, &c.ClientSecret, &c.Role, &c.CreationDate, &c.UpdatedDate, &c.ExpiresIn, &c.IsActive) + }) + if err != nil { + return nil, err + } + + t.credentials = &credentials[0] + } + + return t.credentials, nil +} + +func (t *Token) ToJsonToken() *JsonToken { + return &JsonToken{ + ref: t, + Token: t.Token, + RefreshToken: t.RefreshToken, + CreatedAt: t.GetCreationDate(), + ExpiresIn: t.ExpiresIn, + } } diff --git a/auth/refreshToken.go b/auth/refreshToken.go deleted file mode 100644 index 726392c..0000000 --- a/auth/refreshToken.go +++ /dev/null @@ -1,168 +0,0 @@ -package auth - -import ( - "encoding/json" - "filesystem_service/arrays" - "filesystem_service/customHttp" - "filesystem_service/data" - "filesystem_service/types" - "fmt" - "net/http" - "time" -) - -func RefreshToken(writer http.ResponseWriter, request *http.Request) { - writer.Header().Set("Access-Control-Allow-Origin", "*") - writer.Header().Add("Content-Type", "application/json") - db, err := data.InitDatabase() - defer db.Close() - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - refreshTokenHeader := request.Header.Get("Refresh-Token") - signatureTokenHeader := request.Header.Get("Signature-Token") - - if refreshTokenHeader == "" { - writer.WriteHeader(400) - response, _ := json.Marshal(types.HttpError{ - Code: 400, - Message: "Invalid refresh token", - }) - _, _ = writer.Write(response) - return - } - - ip, err := customHttp.GetUserIp(request) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - tokens, err := db.Query(fmt.Sprintf( - "SELECT * FROM tokens WHERE IP=\"%v\" AND active=TRUE AND signature=\"%v\"", - ip, signatureTokenHeader, - )) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - formattedTokens, err := data.ReadRows[Token](tokens, func(t *Token) error { - return tokens.Scan(&t.Id, &t.Ip, &t.Token, &t.Signature, &t.Type, &t.Active, &t.CreatedAt) - }) - - _, err = json.Marshal(&formattedTokens) - - if err != nil { - println(err.Error()) - } - - if len(formattedTokens) == 0 { - writer.WriteHeader(400) - response, _ := json.Marshal(types.HttpError{ - Code: 400, - Message: "Invalid couple signature and refresh token", - }) - _, _ = writer.Write(response) - return - } - - refreshTokenObj := arrays.Filter[Token](formattedTokens, func(token Token) bool { - return token.Type == "refresh" - })[0] - - if refreshTokenHeader != refreshTokenObj.Token { - writer.WriteHeader(400) - response, _ := json.Marshal(types.HttpError{ - Code: 400, - Message: "Invalid refresh token", - }) - _, _ = writer.Write(response) - return - } - - token, err := GenerateToken(signatureTokenHeader + "." + refreshTokenHeader) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - refreshToken, err := GenerateToken(token) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - _, err = db.Exec(`UPDATE tokens SET active=FALSE WHERE IP=? AND active=TRUE`, ip) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - _, err = db.Exec( - `INSERT INTO tokens (IP, token, signature, type, created_at) VALUES (?, ?, ?, ?, ?)`, - ip, token, signatureTokenHeader, "classic", time.Now().Unix(), - ) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - _, err = db.Exec( - `INSERT INTO tokens (IP, token, signature, type, created_at) VALUES (?, ?, ?, ?, ?)`, - ip, refreshToken, signatureTokenHeader, "refresh", time.Now().Unix(), - ) - if err != nil { - writer.WriteHeader(500) - response, _ := json.Marshal(types.HttpError{ - Code: 500, - Message: err.Error(), - }) - _, _ = writer.Write(response) - return - } - - response, _ := json.Marshal(&GetTokenResponse{ - AccessToken: token, - RefreshToken: refreshToken, - CreatedAt: time.Now().Unix(), - // 1h (en ms) - ExpiresIn: 3600000, - }) - _, _ = writer.Write(response) -} diff --git a/auth/roles/Role.go b/auth/roles/Role.go new file mode 100755 index 0000000..d3a6249 --- /dev/null +++ b/auth/roles/Role.go @@ -0,0 +1,51 @@ +package roles + +import ( + "filesystem_service/arrays" + "strconv" + "strings" +) + +type RoleActions struct { + Id int + Name string +} + +func (r *RoleActions) GetId() int { + return r.Id +} + +func (r *RoleActions) GetName() string { + return r.Name +} + +type Role struct { + Id int + Name string + RoleActionsIds string + RoleActionsNames string + IsActive bool +} + +func (r *Role) GetId() int { + return r.Id +} + +func (r *Role) GetName() string { + return r.Name +} + +func (r *Role) GetRoleActions() []*RoleActions { + names := strings.Split(r.RoleActionsNames, "|") + ids := arrays.Map[string, int](strings.Split(r.RoleActionsIds, "|"), func(s string) int { + i, _ := strconv.Atoi(s) + return i + }) + + return arrays.Map[int, *RoleActions](arrays.Keys(ids), func(i int) *RoleActions { + return &RoleActions{ + ids[i], + names[i], + } + }) +} diff --git a/auth/roles/getUserRole.go b/auth/roles/getUserRole.go new file mode 100755 index 0000000..c94434c --- /dev/null +++ b/auth/roles/getUserRole.go @@ -0,0 +1,54 @@ +package roles + +import ( + "filesystem_service/database" + "fmt" + + "github.com/TwiN/go-color" +) + +func GetUserRole(clientId string) { + if clientId == "" { + fmt.Printf("Vous devez renseigner le client_id.\n") + return + } + + db, err := database.Init() + defer db.Close() + if err != nil { + fmt.Printf("Une erreur est survenue lors de l'initialisation de la base de donnée.\n") + fmt.Printf(err.Error() + "\n") + return + } + + rows, err := db.Query(`SELECT r.id as id, + role_name as name, + group_concat(role_action, '|') as role_actions_ids, + group_concat(role_action_name, '|') as role_actions_names, + r.active as is_active FROM credentials + INNER JOIN roles r ON r.id = credentials.role + INNER JOIN main.roles_link_role_actions rlra ON r.id = rlra.role + INNER JOIN main.role_actions ra on ra.id = rlra.role_action + WHERE client_id = ? AND r.active = TRUE`, clientId) + if err != nil { + fmt.Printf("Une erreur est survenue.\n") + fmt.Printf(err.Error() + "\n") + return + } + + roles, _ := database.ReadRows[Role](rows, func(r *Role) error { + return rows.Scan(&r.Id, &r.Name, &r.RoleActionsIds, &r.RoleActionsNames, &r.IsActive) + }) + + if len(roles) == 0 { + fmt.Printf("Aucun utilisateur actif à été trouvé avec ce client_id.\n") + return + } + + for _, role := range roles { + fmt.Printf(" => %v \n", color.InUnderline(role.GetName())) + for _, roleAction := range role.GetRoleActions() { + fmt.Printf("\t-> %v \n", color.OverGray(color.InBold(roleAction.GetName()))) + } + } +} diff --git a/auth/roles/showRoles.go b/auth/roles/showRoles.go new file mode 100755 index 0000000..2be4bbe --- /dev/null +++ b/auth/roles/showRoles.go @@ -0,0 +1,63 @@ +package roles + +import ( + "database/sql" + "filesystem_service/database" + "fmt" + + "github.com/TwiN/go-color" +) + +func GetRoleIdFromName(db *sql.DB, role string) int { + rows, _ := db.Query(`SELECT id, role_name as name FROM roles WHERE role_name = ?`, role) + findRoles, _ := database.ReadRows[Role](rows, func(r *Role) error { + return rows.Scan(&r.Id, &r.Name) + }) + if len(findRoles) == 0 { + return -1 + } + return findRoles[0].GetId() +} + +func ShowRoles() { + db, err := database.Init() + defer db.Close() + if err != nil { + fmt.Printf("Une erreur est survenue lors de l'initialisation de la base de donnée.\n") + fmt.Printf(err.Error() + "\n") + return + } + + rows, err := db.Query(`SELECT role as id, + role_name as name, + group_concat(role_action, '|') as role_actions_ids, + group_concat(role_action_name, '|') as role_actions_names, + active as is_active + FROM roles_link_role_actions + INNER JOIN roles + ON roles_link_role_actions.role = roles.id + INNER JOIN role_actions + ON roles_link_role_actions.role_action = role_actions.id + GROUP BY role_name`) + if err != nil { + fmt.Printf("Une erreur est survenue lors de la recherche des rôles.\n") + fmt.Printf(err.Error() + "\n") + return + } + + roles, _ := database.ReadRows[Role](rows, func(r *Role) error { + return rows.Scan(&r.Id, &r.Name, &r.RoleActionsIds, &r.RoleActionsNames, &r.IsActive) + }) + + fmt.Printf("Liste des roles disponibles:\n") + if len(roles) == 0 { + fmt.Printf(" == La liste de roles est vide, veuillez en créer ==\n") + return + } + for _, role := range roles { + fmt.Printf(" => %v \n", color.InUnderline(role.GetName())) + for _, roleAction := range role.GetRoleActions() { + fmt.Printf("\t-> %v \n", color.OverGray(color.InBold(roleAction.GetName()))) + } + } +} diff --git a/auth/tokens/checkToken.go b/auth/tokens/checkToken.go new file mode 100755 index 0000000..2ec901f --- /dev/null +++ b/auth/tokens/checkToken.go @@ -0,0 +1,98 @@ +package tokens + +import ( + "encoding/json" + "filesystem_service/auth" + "filesystem_service/database" + //"filesystem_service/auth" + //"filesystem_service/customHttp" + //"filesystem_service/database" + "filesystem_service/types" + "fmt" + //"fmt" + "net/http" + "strings" + "time" +) + +func CheckToken(request *http.Request) (bool, *[]byte, error) { + accessToken := request.Header.Get("Authorization") + if accessToken == "" { + return false, nil, fmt.Errorf("invalid token") + } + accessToken = strings.Replace(accessToken, "Bearer ", "", 1) + + db, err := database.Init() + if err != nil { + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + return false, &response, nil + } + + rows, err := db.Query(`SELECT id, ip, + client_id, access_token, + refresh_token, creation_date, + expires_in, active + FROM tokens + WHERE active = TRUE AND + access_token = ?;`, accessToken) + if err != nil { + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + return false, &response, nil + } + + tokens, err := database.ReadRows[auth.Token](rows, func(t *auth.Token) error { + return rows.Scan( + &t.Id, &t.Ip, + &t.ClientId, &t.Token, + &t.RefreshToken, &t.CreatedAt, + &t.ExpiresIn, &t.Active, + ) + }) + if len(tokens) == 0 { + return false, nil, fmt.Errorf("invalid token") + } + token := tokens[0] + + if token.GetCreationDate()+int64(token.ExpiresIn) < time.Now().Unix() { + if _, err = db.Exec(`UPDATE tokens SET active = FALSE WHERE active = TRUE AND access_token = ?`, accessToken); err != nil { + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + return false, &response, nil + } + + return false, nil, fmt.Errorf("invalid token") + } + + return true, nil, nil +} + +func IsAuthorized(writer http.ResponseWriter, request *http.Request) bool { + if _, resp, err := CheckToken(request); err != nil || resp != nil { + var message types.HttpError + code := 403 + if err != nil { + message = types.HttpError{ + Code: 403, + Message: err.Error(), + } + } else if resp != nil { + var data types.HttpError + _ = json.Unmarshal(*resp, &data) + code = data.Code + message = data + } + writer.WriteHeader(code) + response, _ := json.Marshal(&message) + _, _ = writer.Write(response) + return false + } + return true +} diff --git a/auth/tokens/generateToken.go b/auth/tokens/generateToken.go new file mode 100755 index 0000000..b0f54ed --- /dev/null +++ b/auth/tokens/generateToken.go @@ -0,0 +1,9 @@ +package tokens + +import ( + "filesystem_service/auth/credentials" +) + +func GenerateToken() (string, error) { + return credentials.CreateNewToken(credentials.AvailableCharacters, 60), nil +} diff --git a/auth/tokens/getToken.go b/auth/tokens/getToken.go new file mode 100755 index 0000000..d94a18a --- /dev/null +++ b/auth/tokens/getToken.go @@ -0,0 +1,171 @@ +package tokens + +import ( + "encoding/base64" + "encoding/json" + "filesystem_service/auth" + "filesystem_service/customHttp" + "filesystem_service/database" + "filesystem_service/types" + "fmt" + "net/http" + "strings" +) + +func GetToken(writer http.ResponseWriter, request *http.Request) { + writer.Header().Add("Content-Type", "application/json") + + db, err := database.Init() + defer db.Close() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + queryString := request.URL.Query() + clientId := queryString.Get("client_id") + clientSecret := queryString.Get("client_secret") + + if clientId == "" || clientSecret == "" { + basicToken := request.Header.Get("Authorization") + if strings.Contains(basicToken, "Basic ") { + basicToken = strings.Replace(basicToken, "Basic ", "", 1) + _basicToken, err := base64.StdEncoding.DecodeString(basicToken) + if err != nil { + customHttp.WriteError(writer, 403, fmt.Errorf("You must input your client_id and client_secret credentials.")) + return + } + basicToken = string(_basicToken) + + splitToken := strings.Split(basicToken, ":") + clientId = splitToken[0] + clientSecret = splitToken[1] + } else { + customHttp.WriteError(writer, 403, fmt.Errorf("You must input your client_id and client_secret credentials.")) + return + } + } + + foundCredentials, err := db.Query(`SELECT + client_id, client_secret, + role_name as role, + creation_date, updated_date, + expires_in, c.active as active + FROM credentials c INNER JOIN roles r ON r.id = c.role + WHERE c.active = TRUE AND + client_id = ? AND + client_secret = ?;`, + clientId, clientSecret) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + credentials, err := database.ReadRows[auth.Credential](foundCredentials, func(t *auth.Credential) error { + return foundCredentials.Scan( + &t.ClientId, &t.ClientSecret, + &t.Role, &t.CreationDate, + &t.UpdatedDate, &t.ExpiresIn, + &t.IsActive, + ) + }) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + if len(credentials) == 0 { + customHttp.WriteError(writer, 403, fmt.Errorf("You are not identified")) + return + } + + token, err := GenerateToken() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + refreshToken, err := GenerateToken() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + ip, err := customHttp.GetUserIp(request) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + _, err = db.Exec(`UPDATE tokens SET active = FALSE WHERE ip = ? AND active = TRUE`, ip) + if err != nil { + writer.WriteHeader(500) + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + _, _ = writer.Write(response) + return + } + + result, err := db.Exec( + `INSERT INTO tokens (ip, client_id, access_token, refresh_token, active) VALUES (?, ?, ?, ?, TRUE)`, + ip, clientId, token, refreshToken, + ) + if err != nil { + writer.WriteHeader(500) + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + _, _ = writer.Write(response) + return + } + + lastInsertedId, err := result.LastInsertId() + + rows, err := db.Query(`SELECT id, ip, + client_id, access_token, + refresh_token, creation_date, + expires_in, active + FROM tokens + WHERE id = ?;`, lastInsertedId) + if err != nil { + writer.WriteHeader(500) + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + _, _ = writer.Write(response) + return + } + tokens, err := database.ReadRows[auth.Token](rows, func(t *auth.Token) error { + return rows.Scan( + &t.Id, &t.Ip, &t.ClientId, + &t.Token, &t.RefreshToken, + &t.CreatedAt, &t.ExpiresIn, + &t.Active, + ) + }) + if err != nil { + writer.WriteHeader(500) + response, _ := json.Marshal(types.HttpError{ + Code: 500, + Message: err.Error(), + }) + _, _ = writer.Write(response) + return + } + if len(tokens) == 0 { + writer.WriteHeader(403) + response, _ := json.Marshal(types.HttpError{ + Code: 403, + Message: "Invalid token.", + }) + _, _ = writer.Write(response) + return + } + lastCreatedToken := tokens[0] + + response, _ := json.Marshal(lastCreatedToken.ToJsonToken()) + _, _ = writer.Write(response) +} diff --git a/auth/tokens/refreshToken.go b/auth/tokens/refreshToken.go new file mode 100755 index 0000000..6f07c9d --- /dev/null +++ b/auth/tokens/refreshToken.go @@ -0,0 +1,153 @@ +package tokens + +import ( + "encoding/json" + "filesystem_service/auth" + "filesystem_service/customHttp" + "filesystem_service/database" + "fmt" + "net/http" +) + +func RefreshToken(writer http.ResponseWriter, request *http.Request) { + writer.Header().Add("Content-Type", "application/json") + + clientId := request.URL.Query().Get("client_id") + clientSecret := request.URL.Query().Get("client_secret") + + if clientId == "" || clientSecret == "" { + customHttp.WriteError(writer, 403, fmt.Errorf("you must input client_id and client_secret for refresh your token.")) + return + } + + db, err := database.Init() + defer db.Close() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + refreshToken := request.Header.Get("Refresh-Token") + if refreshToken == "" { + var body *struct { + RefreshToken string `json:"refresh_token"` + } + _ = json.NewDecoder(request.Body).Decode(body) + + if body.RefreshToken == "" { + customHttp.WriteError(writer, 400, fmt.Errorf("Invalid refresh token")) + return + } + refreshToken = body.RefreshToken + } + + ip, err := customHttp.GetUserIp(request) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + activeTokens, _ := db.Query(`SELECT client_id FROM tokens WHERE active = TRUE AND ip = ?`, ip) + _tokens, _ := database.ReadRows[auth.Token](activeTokens, func(t *auth.Token) error { + return activeTokens.Scan(&t.ClientId) + }) + + tokenCredentials, _ := _tokens[0].GetCredentials() + if clientSecret != tokenCredentials.ClientSecret { + customHttp.WriteError(writer, 403, fmt.Errorf("Invalid credentials.")) + return + } + + rows, err := db.Query(`SELECT id, ip, + client_id, access_token, + refresh_token, creation_date, + expires_in, active + FROM tokens + WHERE active = TRUE AND + ip = ? AND + refresh_token = ?;`, ip, refreshToken) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + tokens, err := database.ReadRows[auth.Token](rows, func(t *auth.Token) error { + return rows.Scan( + &t.Id, &t.Ip, &t.ClientId, + &t.Token, &t.RefreshToken, + &t.CreatedAt, &t.ExpiresIn, + &t.Active, + ) + }) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + if len(tokens) == 0 { + customHttp.WriteError(writer, 400, fmt.Errorf("Invalid couple signature and refresh token")) + return + } + + if refreshToken != tokens[0].RefreshToken { + customHttp.WriteError(writer, 400, fmt.Errorf("Invalid refresh token")) + return + } + + newToken, err := GenerateToken() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + newRefreshToken, err := GenerateToken() + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + _, err = db.Exec(`UPDATE tokens SET active = FALSE + WHERE ip = ? AND + active = TRUE`, ip) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + result, err := db.Exec( + `INSERT INTO tokens (ip, client_id, access_token, refresh_token, active) VALUES (?, ?, ?, ?, TRUE)`, + ip, tokens[0].ClientId, newToken, newRefreshToken, + ) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + + lastInsertedId, err := result.LastInsertId() + + rows, err = db.Query(`SELECT id, ip, + client_id, access_token, + refresh_token, creation_date, + expires_in, active + FROM tokens + WHERE id = ?`, lastInsertedId) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + tokens, err = database.ReadRows[auth.Token](rows, func(t *auth.Token) error { + return rows.Scan( + &t.Id, &t.Ip, &t.ClientId, + &t.Token, &t.RefreshToken, + &t.CreatedAt, &t.ExpiresIn, + &t.Active, + ) + }) + if err != nil { + customHttp.WriteError(writer, 500, err) + return + } + lastCreatedToken := tokens[0] + + response, _ := json.Marshal(lastCreatedToken.ToJsonToken()) + _, _ = writer.Write(response) +} diff --git a/checkValidity.go b/checkValidity.go old mode 100644 new mode 100755 index 5c38b0a..da46f5b --- a/checkValidity.go +++ b/checkValidity.go @@ -8,9 +8,10 @@ import ( func CheckValidity(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") + //customHttp.EnableCors(&writer, request) writer.Header().Add("Content-Type", "application/json") - response := &types.CheckValidity{true} + response := &types.CheckValidity{IsValid: true} _json, err := json.Marshal(response) if err != nil { diff --git a/consoleColors/main_darwin.go b/consoleColors/main_darwin.go new file mode 100755 index 0000000..9715993 --- /dev/null +++ b/consoleColors/main_darwin.go @@ -0,0 +1,11 @@ +package consoleColors + +var Reset = "\033[0m" +var Red = "\033[31m" +var Green = "\033[32m" +var Yellow = "\033[33m" +var Blue = "\033[34m" +var Purple = "\033[35m" +var Cyan = "\033[36m" +var Gray = "\033[37m" +var White = "\033[97m" diff --git a/consoleColors/main_linux.go b/consoleColors/main_linux.go new file mode 100755 index 0000000..9715993 --- /dev/null +++ b/consoleColors/main_linux.go @@ -0,0 +1,11 @@ +package consoleColors + +var Reset = "\033[0m" +var Red = "\033[31m" +var Green = "\033[32m" +var Yellow = "\033[33m" +var Blue = "\033[34m" +var Purple = "\033[35m" +var Cyan = "\033[36m" +var Gray = "\033[37m" +var White = "\033[97m" diff --git a/consoleColors/main_windows.go b/consoleColors/main_windows.go new file mode 100755 index 0000000..fec2daf --- /dev/null +++ b/consoleColors/main_windows.go @@ -0,0 +1,11 @@ +package consoleColors + +var Reset = "" +var Red = "" +var Green = "" +var Yellow = "" +var Blue = "" +var Purple = "" +var Cyan = "" +var Gray = "" +var White = "" diff --git a/customFs/directory.go b/customFs/directory.go old mode 100644 new mode 100755 diff --git a/customFs/file.go b/customFs/file.go old mode 100644 new mode 100755 diff --git a/customFs/helpers.go b/customFs/helpers.go old mode 100644 new mode 100755 diff --git a/customFs/main_darwin.go b/customFs/main_darwin.go old mode 100644 new mode 100755 diff --git a/customFs/main_linux.go b/customFs/main_linux.go old mode 100644 new mode 100755 diff --git a/customFs/main_windows.go b/customFs/main_windows.go old mode 100644 new mode 100755 diff --git a/customHttp/acceptOptions.go b/customHttp/acceptOptions.go new file mode 100755 index 0000000..c1825fe --- /dev/null +++ b/customHttp/acceptOptions.go @@ -0,0 +1,7 @@ +package customHttp + +import "net/http" + +func AcceptOptions(writer http.ResponseWriter, request *http.Request) { + return +} diff --git a/customHttp/cors.go b/customHttp/cors.go new file mode 100755 index 0000000..d016e55 --- /dev/null +++ b/customHttp/cors.go @@ -0,0 +1,29 @@ +package customHttp + +import ( + "net/http" +) + +func Cors(handler http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + writer.Header().Set( + "Access-Control-Allow-Origin", + request.Header.Get("Origin"), + ) + writer.Header().Set( + "Access-Control-Allow-Methods", + "POST,GET,OPTIONS,PUT,PATCH,DELETE", + ) + writer.Header().Set( + "Access-Control-Allow-Headers", + "Access-Control-Allow-Origin, Access-Control-Allow-Methods, Accept, Content-Length, Accept-Encoding, X-CSRF-Token, Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With", + ) + + if request.Method == "OPTIONS" { + writer.WriteHeader(http.StatusOK) + return + } + + handler(writer, request) + } +} diff --git a/customHttp/error.go b/customHttp/error.go new file mode 100755 index 0000000..5c8452d --- /dev/null +++ b/customHttp/error.go @@ -0,0 +1,16 @@ +package customHttp + +import ( + "encoding/json" + "filesystem_service/types" + "net/http" +) + +func WriteError(writer http.ResponseWriter, code int, err error) { + writer.WriteHeader(code) + response, _ := json.Marshal(types.HttpError{ + Code: code, + Message: err.Error(), + }) + _, _ = writer.Write(response) +} diff --git a/customHttp/getAddr.go b/customHttp/getAddr.go old mode 100644 new mode 100755 diff --git a/customHttp/getUserIp.go b/customHttp/getUserIp.go old mode 100644 new mode 100755 diff --git a/data/main.go b/data/main.go deleted file mode 100644 index 32ef11f..0000000 --- a/data/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package data - -import ( - "database/sql" -) - -func ConnectDatabase() (*sql.DB, error) { - return sql.Open("sqlite", "./file-system-service-oauth.sqlite") -} - -func InitDatabase() (*sql.DB, error) { - db, err := ConnectDatabase() - if err != nil { - return nil, err - } - - //ENUM('classic', 'refresh') - _, err = db.Exec("CREATE TABLE IF NOT EXISTS tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, IP TEXT NOT NULL, token TEXT, signature TEXT, type TEXT NOT NULL DEFAULT 'classic', active BOOLEAN NOT NULL DEFAULT true, created_at DATETIME NOT NULL)") - if err != nil { - return nil, err - } - - _, err = db.Exec("CREATE TABLE IF NOT EXISTS signatures (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, signature TEXT, active BOOLEAN DEFAULT true)") - if err != nil { - return nil, err - } - - return db, nil -} - -func ReadRows[T any](rows *sql.Rows, scan func(t *T) error) (results []T, _err error) { - _err = nil - for rows.Next() { - var line T - if err := scan(&line); err != nil { - _err = err - break - } - results = append(results, line) - } - return results, _err -} diff --git a/database/main.go b/database/main.go new file mode 100755 index 0000000..60d5f09 --- /dev/null +++ b/database/main.go @@ -0,0 +1,116 @@ +package database + +import ( + "database/sql" +) + +func Connect() (*sql.DB, error) { + return sql.Open("sqlite", "./file-system-service-oauth.sqlite") +} + +func Init() (*sql.DB, error) { + db, err := Connect() + if err != nil { + return nil, err + } + + if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS role_actions ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + role_action_name VARCHAR(255) + );`); err != nil { + return nil, err + } + if _, err = db.Exec(`INSERT OR IGNORE INTO role_actions (id, role_action_name) VALUES + (1, 'read_dir'), + (2, 'create_dir'), + (3, 'delete_dir'), + (4, 'rename_dir'), + (5, 'read_file'), + (6, 'create_file'), + (7, 'delete_file'), + (8, 'rename_file'), + (9, 'update_file_content');`); err != nil { + return nil, err + } + + if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS roles ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + role_name VARCHAR(255) NOT NULL, + active BOOLEAN NOT NULL DEFAULT FALSE + );`); err != nil { + return nil, err + } + if _, err = db.Exec(`INSERT OR IGNORE INTO roles (id, role_name, active) VALUES + (1, 'readwrite', TRUE), + (2, 'readonly', TRUE);`); err != nil { + return nil, err + } + + if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS roles_link_role_actions ( + role_name VARCHAR(255) NOT NULL, + role_action_name VARCHAR(255) NOT NULL, + PRIMARY KEY (role_name, role_action_name), + FOREIGN KEY (role_name) REFERENCES roles(role_name), + FOREIGN KEY (role_action_name) REFERENCES role_actions(role_action_name) + );`); err != nil { + return nil, err + } + if _, err = db.Exec(`INSERT OR IGNORE INTO roles_link_role_actions (role, role_action) VALUES + (1, 1), + (1, 2), + (1, 3), + (1, 4), + (1, 5), + (1, 6), + (1, 7), + (1, 8), + (1, 9), + (2, 1), + (2, 5);`); err != nil { + return nil, err + } + + if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS credentials ( + client_id VARCHAR(255) PRIMARY KEY, + client_secret VARCHAR(255) NOT NULL, + role INTEGER NOT NULL, + creation_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_date TIMESTAMP DEFAULT NULL, +-- 1 an (en timestamp) + expires_in INTEGER DEFAULT 31536000, + active BOOLEAN NOT NULL DEFAULT FALSE, + FOREIGN KEY (role) REFERENCES roles(id) + )`); err != nil { + return nil, err + } + + if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS tokens ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + ip VARCHAR(255) NOT NULL, + client_id VARCHAR(255), + access_token VARCHAR(255) NOT NULL, + refresh_token VARCHAR(255) NOT NULL, +-- 1h (en timestamp) + expires_in INT DEFAULT NULL DEFAULT 3600, + creation_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + active BOOLEAN NOT NULL DEFAULT FALSE, + FOREIGN KEY (client_id) REFERENCES credentials(client_id) + )`); err != nil { + return nil, err + } + + return db, nil +} + +func ReadRows[T any](rows *sql.Rows, scan func(t *T) error) (results []T, _err error) { + _err = nil + for rows.Next() { + var line T + if err := scan(&line); err != nil { + _err = err + break + } + results = append(results, line) + } + return results, _err +} diff --git a/directories/createDirectory.go b/directories/createDirectory.go old mode 100644 new mode 100755 index d988482..931cf8f --- a/directories/createDirectory.go +++ b/directories/createDirectory.go @@ -2,9 +2,9 @@ package directories import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" - "filesystem_service/types" + "filesystem_service/customHttp" "net/http" ) @@ -12,31 +12,21 @@ func CreateDirectory(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } var body fs.Directory if err := json.NewDecoder(request.Body).Decode(&body); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } d := fs.NewDirectory(fs.BuildDirectoryCompletePath(body)) if _, err := d.Create(); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/directories/deleteDirectory.go b/directories/deleteDirectory.go old mode 100644 new mode 100755 index f77313d..2e82b36 --- a/directories/deleteDirectory.go +++ b/directories/deleteDirectory.go @@ -2,8 +2,9 @@ package directories import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" + "filesystem_service/customHttp" "filesystem_service/types" "net/http" "strings" @@ -13,7 +14,7 @@ func DeleteDirectory(writer http.ResponseWriter, request *http.Request) { writer.Header().Add("Content-Type", "application/json") writer.Header().Set("Access-Control-Allow-Origin", "*") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -31,12 +32,7 @@ func DeleteDirectory(writer http.ResponseWriter, request *http.Request) { } if err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/directories/getDirectoryItemList.go b/directories/getDirectoryItemList.go old mode 100644 new mode 100755 index 2aa277f..483eb79 --- a/directories/getDirectoryItemList.go +++ b/directories/getDirectoryItemList.go @@ -2,9 +2,9 @@ package directories import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" - "filesystem_service/types" + "filesystem_service/customHttp" "net/http" "strings" ) @@ -13,7 +13,7 @@ func GetFileSystem(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -28,12 +28,7 @@ func GetFileSystem(writer http.ResponseWriter, request *http.Request) { code = 404 } - writer.WriteHeader(code) - response, _ := json.Marshal(&types.HttpError{ - Code: code, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, code, err) return } diff --git a/directories/renameDirectory.go b/directories/renameDirectory.go old mode 100644 new mode 100755 index c6c12a6..9fcbd18 --- a/directories/renameDirectory.go +++ b/directories/renameDirectory.go @@ -2,9 +2,9 @@ package directories import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" - "filesystem_service/types" + "filesystem_service/customHttp" "net/http" "strings" ) @@ -13,19 +13,14 @@ func RenameDirectory(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } var body fs.Directory if err := json.NewDecoder(request.Body).Decode(&body); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } @@ -35,12 +30,7 @@ func RenameDirectory(writer http.ResponseWriter, request *http.Request) { nd := fs.NewDirectory(fs.BuildDirectoryCompletePath(body)) if _, err := d.Rename(nd); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/files/createFile.go b/files/createFile.go old mode 100644 new mode 100755 index 43088ad..9ad4a59 --- a/files/createFile.go +++ b/files/createFile.go @@ -2,9 +2,9 @@ package files import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" - "filesystem_service/types" + "filesystem_service/customHttp" "net/http" ) @@ -31,41 +31,26 @@ func CreateFile(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } file, content, err := getMultipartKeys(request) if err != nil { writer.Header().Add("Content-Type", "application/json") - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } f := fs.NewFile(fs.BuildFileCompletePath(file)) if _, err = f.Create(); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } if _, err = f.SetContent([]byte(content)); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/files/deleteFile.go b/files/deleteFile.go old mode 100644 new mode 100755 index 16e9dad..6fa9e87 --- a/files/deleteFile.go +++ b/files/deleteFile.go @@ -2,8 +2,9 @@ package files import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" + "filesystem_service/customHttp" "filesystem_service/types" "net/http" "strings" @@ -13,7 +14,7 @@ func DeleteFile(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -22,12 +23,7 @@ func DeleteFile(writer http.ResponseWriter, request *http.Request) { f := fs.NewFile(path) if _, err := f.Delete(); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/files/formats.go b/files/formats.go old mode 100644 new mode 100755 diff --git a/files/getFileContent.go b/files/getFileContent.go old mode 100644 new mode 100755 index 64f9300..8e2921a --- a/files/getFileContent.go +++ b/files/getFileContent.go @@ -1,10 +1,9 @@ package files import ( - "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" - "filesystem_service/types" + "filesystem_service/customHttp" "fmt" "net/http" "strings" @@ -13,7 +12,7 @@ import ( func GetFileContent(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -24,12 +23,7 @@ func GetFileContent(writer http.ResponseWriter, request *http.Request) { if err != nil { writer.Header().Add("Content-Type", "application/json") - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } @@ -38,11 +32,7 @@ func GetFileContent(writer http.ResponseWriter, request *http.Request) { writer.Header().Add("Content-Type", fileFormats[extension]) fileContent, err := file.GetContent() if err != nil { - response, _ := json.Marshal(&types.HttpError{ - Code: 404, - Message: fmt.Sprintf("open %s not found", path), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 404, fmt.Errorf(fmt.Sprintf("open %s not found", path))) return } diff --git a/files/updateFile.go b/files/updateFile.go old mode 100644 new mode 100755 index 56872a6..ea99140 --- a/files/updateFile.go +++ b/files/updateFile.go @@ -2,8 +2,9 @@ package files import ( "encoding/json" - "filesystem_service/auth" + "filesystem_service/auth/tokens" fs "filesystem_service/customFs" + "filesystem_service/customHttp" "filesystem_service/types" "io" "net/http" @@ -14,7 +15,7 @@ func RenameFile(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -23,24 +24,14 @@ func RenameFile(writer http.ResponseWriter, request *http.Request) { path := fs.GetRoot() + strings.Replace(request.PathValue("path"), "%2F", "/", -1) if err := json.NewDecoder(request.Body).Decode(&renamedFile); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } f := fs.NewFile(path) if _, err := f.Rename(fs.NewFile(fs.BuildFileCompletePath(renamedFile))); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } @@ -54,7 +45,7 @@ func UpdateFileContent(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Access-Control-Allow-Origin", "*") writer.Header().Add("Content-Type", "application/json") - if !auth.IsAuthorized(writer, request) { + if !tokens.IsAuthorized(writer, request) { return } @@ -66,23 +57,13 @@ func UpdateFileContent(writer http.ResponseWriter, request *http.Request) { text, err := io.ReadAll(request.Body) if err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } body = text if _, err = f.SetContent(body); err != nil { - writer.WriteHeader(400) - response, _ := json.Marshal(&types.HttpError{ - Code: 400, - Message: err.Error(), - }) - _, _ = writer.Write(response) + customHttp.WriteError(writer, 400, err) return } diff --git a/flags/flags.go b/flags/flags.go old mode 100644 new mode 100755 index 4eed4ab..8fc6208 --- a/flags/flags.go +++ b/flags/flags.go @@ -11,7 +11,13 @@ type Flags struct { portEnv *string hostEnv *string - generateSignature *bool + generateCredentials *bool + updateCredentials *bool + showRoles *bool + showUserRole *bool + + role *string + clientId *string } func (f *Flags) GetPort() int { @@ -29,6 +35,29 @@ func (f *Flags) GetHost() string { return *f.host } -func (f *Flags) IsGenerateSignature() bool { - return !(f.generateSignature == nil || *f.generateSignature == false) +func (f *Flags) IsGenerateCredentials() bool { + return !(f.generateCredentials == nil || *f.generateCredentials == false) +} + +func (f *Flags) IsUpdateCredentials() bool { + return !(f.updateCredentials == nil || *f.updateCredentials == false) +} + +func (f *Flags) IsShowRoles() bool { + return !(f.showRoles == nil || *f.showRoles == false) +} + +func (f *Flags) IsShowUserRole() bool { + return !(f.showUserRole == nil || *f.showUserRole == false) +} + +func (f *Flags) GetRole() string { + if !(f.role == nil || *f.role == "") { + return *f.role + } + return "" +} + +func (f *Flags) GetClientId() string { + return *f.clientId } diff --git a/flags/getFlags.go b/flags/getFlags.go old mode 100644 new mode 100755 index 4aa2395..84be3e6 --- a/flags/getFlags.go +++ b/flags/getFlags.go @@ -8,7 +8,13 @@ var host = flag.String("host", "127.0.0.1", "Domaine ou IP de la machine qui exp var portEnv = flag.String("port-env", "", "Variable d'environement où trouver le port d'exposition de l'application.") var hostEnv = flag.String("host-env", "", "Variable d'environement où trouver le domaine ou l'IP de la machine qui expose le sercice.") -var generateSignature = flag.Bool("generate-signature", false, "Active l'option de génération du token de signature pour l'utilisateur.") +var generateCredentials = flag.Bool("generate-credentials", false, "Active l'option de génération des credentials pour l'utilisateur.") +var updateCredentials = flag.Bool("update-credentials", false, "Active l'option de modification des credentials pour l'utilisateur.") +var showUserRole = flag.Bool("show-user-role", false, "Active l'option de d'affichage du rôle de l'utilisateur.") + +var showRoles = flag.Bool("show-roles", false, "Afficher la liste des rôles disponibles.") +var role = flag.String("role", "readonly", "Rensègne le rôle selectionné.") +var clientId = flag.String("client_id", "", "Rensègne le client_id.") func GetFlags() Flags { if !flag.Parsed() { @@ -20,6 +26,11 @@ func GetFlags() Flags { host, portEnv, hostEnv, - generateSignature, + generateCredentials, + updateCredentials, + showRoles, + showUserRole, + role, + clientId, } } diff --git a/go.mod b/go.mod old mode 100644 new mode 100755 index 372d3d4..b6fb581 --- a/go.mod +++ b/go.mod @@ -3,15 +3,55 @@ module filesystem_service go 1.22.0 require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/TwiN/go-color v1.4.1 // indirect github.com/atotto/clipboard v0.1.4 // indirect + github.com/bytedance/sonic v1.11.3 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.19.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/pelletier/go-toml/v2 v2.2.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - golang.org/x/sys v0.16.0 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/files/v2 v2.0.0 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect + github.com/swaggo/http-swagger v1.3.4 // indirect + github.com/swaggo/http-swagger/v2 v2.0.2 // indirect + github.com/swaggo/swag v1.16.3 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.7.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.19.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.41.0 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum old mode 100644 new mode 100755 index a2e3d9d..1d9b580 --- a/go.sum +++ b/go.sum @@ -1,22 +1,192 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/TwiN/go-color v1.4.1 h1:mqG0P/KBgHKVqmtL5ye7K0/Gr4l6hTksPgTgMk3mUzc= +github.com/TwiN/go-color v1.4.1/go.mod h1:WcPf/jtiW95WBIsEeY1Lc/b8aaWoiqQpu5cf8WFxu+s= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA= +github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= +github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= +github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= +github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= +github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg= +github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= +github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI= +github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= +golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk= @@ -31,3 +201,5 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/integer/random.go b/integer/random.go new file mode 100755 index 0000000..07e84e7 --- /dev/null +++ b/integer/random.go @@ -0,0 +1,7 @@ +package integer + +import "math/rand" + +func RandomBetween(min, max int) int { + return min + rand.Intn(max-min) +} diff --git a/main.go b/main.go old mode 100644 new mode 100755 index 54d5666..80e5bce --- a/main.go +++ b/main.go @@ -2,20 +2,23 @@ package main import ( "filesystem_service/actions" - "filesystem_service/auth" + "filesystem_service/auth/tokens" "filesystem_service/customHttp" "filesystem_service/directories" "filesystem_service/files" + "filesystem_service/swagger" "fmt" "net/http" "os" "os/signal" "syscall" + httpSwagger "github.com/swaggo/http-swagger/v2" _ "modernc.org/sqlite" ) func main() { + // TODO maintenant que la génération de credentials est faite, gérer la génération et la validation de tokens. if !actions.Exec() { addr := customHttp.GetAddr() @@ -23,20 +26,32 @@ func main() { server.HandleFunc("/check-validity", CheckValidity) // ok - server.HandleFunc("POST /auth/get-token", auth.GetToken) - server.HandleFunc("PUT /auth/get-token", auth.RefreshToken) + server.HandleFunc("OPTIONS /auth/get-token", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("POST /auth/get-token", customHttp.Cors(tokens.GetToken)) // ok + server.HandleFunc("PUT /auth/get-token", customHttp.Cors(tokens.RefreshToken)) // ok - server.HandleFunc("/file-system/{path...}", directories.GetFileSystem) // ok + server.HandleFunc("OPTIONS /file-system/{path...}", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("/file-system/{path...}", customHttp.Cors(directories.GetFileSystem)) // ok - server.HandleFunc("POST /directory", directories.CreateDirectory) // ok - server.HandleFunc("PATCH /directory/{path...}", directories.RenameDirectory) // ok - server.HandleFunc("DELETE /directory/{path...}", directories.DeleteDirectory) // ok + server.HandleFunc("OPTIONS /directory", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("POST /directory", customHttp.Cors(directories.CreateDirectory)) // ok + server.HandleFunc("OPTIONS /directory/{path...}", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("PATCH /directory/{path...}", customHttp.Cors(directories.RenameDirectory)) // ok + server.HandleFunc("DELETE /directory/{path...}", customHttp.Cors(directories.DeleteDirectory)) // ok - server.HandleFunc("/file/{path...}", files.GetFileContent) // ok - server.HandleFunc("POST /file", files.CreateFile) // ok - server.HandleFunc("PATCH /file/{path...}", files.RenameFile) // ok - server.HandleFunc("PUT /file/{path...}", files.UpdateFileContent) // ok - server.HandleFunc("DELETE /file/{path...}", files.DeleteFile) // ok + server.HandleFunc("OPTIONS /file/{path...}", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("/file/{path...}", customHttp.Cors(files.GetFileContent)) // ok + server.HandleFunc("PATCH /file/{path...}", customHttp.Cors(files.RenameFile)) // ok + server.HandleFunc("PUT /file/{path...}", customHttp.Cors(files.UpdateFileContent)) // ok + server.HandleFunc("DELETE /file/{path...}", customHttp.Cors(files.DeleteFile)) // ok + server.HandleFunc("OPTIONS /file", customHttp.Cors(customHttp.AcceptOptions)) // ok + server.HandleFunc("POST /file", customHttp.Cors(files.CreateFile)) // ok + + server.HandleFunc("/swagger.json", swagger.DefinitionRoute) // ok + server.HandleFunc("/swagger.yaml", swagger.DefinitionRoute) // ok + server.HandleFunc("/swagger.yml", swagger.DefinitionRoute) // ok + + server.HandleFunc("/swagger/*", httpSwagger.Handler(httpSwagger.URL("/swagger.json"))) // ok c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) diff --git a/swagger/definition.go b/swagger/definition.go new file mode 100755 index 0000000..15c861c --- /dev/null +++ b/swagger/definition.go @@ -0,0 +1,49 @@ +package swagger + +import ( + _ "embed" + "net/http" + "strings" +) + +//go:embed swagger.json +var swaggerJson []byte + +//go:embed swagger.yaml +var swaggerYaml []byte + +type associatedToExtension struct { + mimeType string + content []byte +} + +var extensions = map[string]associatedToExtension{ + ".json": { + mimeType: "application/json", + content: swaggerJson, + }, + ".yaml": { + mimeType: "application/x-yaml", + content: swaggerYaml, + }, + ".yml": { + mimeType: "application/x-yaml", + content: swaggerYaml, + }, +} + +func DefinitionRoute(writer http.ResponseWriter, request *http.Request) { + path := request.URL.Path + + if strings.HasPrefix(path, "/swagger") { + for ext, detail := range extensions { + if strings.HasSuffix(path, ext) { + writer.Header().Add("Content-Type", detail.mimeType) + _, _ = writer.Write(detail.content) + return + } + } + } + + http.NotFound(writer, request) +} diff --git a/swagger/docs.go b/swagger/docs.go new file mode 100755 index 0000000..be2e711 --- /dev/null +++ b/swagger/docs.go @@ -0,0 +1,36 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package swagger + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": {} +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/swagger/swagger.json b/swagger/swagger.json new file mode 100755 index 0000000..bab072f --- /dev/null +++ b/swagger/swagger.json @@ -0,0 +1,866 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "File system Service", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://{host}:{port}", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "default": "3000", + "description": "Port where is exposed service." + } + } + } + ], + "components": { + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "/auth/get-token", + "scopes": { + "readwrite": "lecture et ecriture", + "readonly": "lecture seule" + } + } + } + } + }, + "requestBodies": { + "FileSystemItem": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileSystemItem" + } + } + } + } + }, + "schemas": { + "ValidityChecked": { + "description": "Validity checked", + "type": "object", + "properties": { + "isValid": { + "type": "boolean", + "enum": [ + true, + false + ] + } + } + }, + "HttpError": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "integer" + }, + "message": { + "type": "string" + } + } + }, + "FileSystemItemWithoutExtension": { + "type": "object", + "required": [ + "type", + "path", + "name" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "file", + "directory" + ] + }, + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "symlink": { + "type": "string" + } + } + }, + "FileSystemItemExtension": { + "type": "object", + "properties": { + "extension": { + "type": "string", + "enum": [ + "", + ".txt", + ".pdf", + ".json", + ".xml" + ] + } + } + }, + "FileSystemItem": { + "allOf": [ + { + "$ref": "#/components/schemas/FileSystemItemWithoutExtension" + }, + { + "$ref": "#/components/schemas/FileSystemItemExtension" + } + ] + }, + "ResponseStatus": { + "type": "object", + "properties": { + "status": { + "enum": [ + "success", + "error" + ] + } + } + }, + "AccessToken": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "expires_in": { + "type": "integer" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + { + "name": "File System", + "description": "All concerns file system." + }, + { + "name": "Files", + "description": "All concerns files." + }, + { + "name": "Directories", + "description": "All concerns directories." + } + ], + "paths": { + "/check-validity": { + "get": { + "description": "New endpoint", + "responses": { + "200": { + "description": "Validated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidityChecked" + } + } + } + } + } + } + }, + "/file-system/{path}": { + "summary": "Get all content of directory (flat)", + "description": "Get all elements in search directory (in {path})", + "parameters": [ + { + "name": "path", + "description": "Path of file to get.", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "path", + "default": "home/nchoquet" + }, + "style": "simple", + "example": "home/nchoquet" + } + ], + "get": { + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "File System" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemItemWithoutExtension" + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + } + }, + "/file-system/": { + "summary": "Get all content of root directory (flat)", + "description": "Get all elements in search directory (in root of your system)", + "get": { + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "File System" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemItemWithoutExtension" + } + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + } + }, + "/directory": { + "summary": "Create new directory", + "description": "Create new directory", + "post": { + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Directories" + ], + "requestBody": { + "$ref": "#/components/requestBodies/FileSystemItem" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileSystemItem" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + } + }, + "/directory/{path}": { + "parameters": [ + { + "name": "path", + "description": "Path of file to rename.", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "path", + "default": "home/nchoquet" + }, + "style": "simple", + "example": "home/nchoquet" + } + ], + "patch": { + "summary": "Rename selected directory", + "description": "Rename selected directory", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Directories" + ], + "requestBody": { + "$ref": "#/components/requestBodies/FileSystemItem" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileSystemItem" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + }, + "delete": { + "summary": "Delete a directory", + "description": "Delete a directory", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Directories" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + } + } + } + }, + "/file": { + "summary": "Create new file", + "description": "Create new file with or without content", + "post": { + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Files" + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "allOf": [ + { + "$ref": "#/components/requestBodies/FileSystemItem" + } + ] + }, + "content": { + "oneOf": [ + { + "type": "object" + }, + { + "type": "array" + }, + { + "type": "string" + }, + { + "type": "string", + "format": "binary" + } + ] + } + } + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileSystemItem" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + } + }, + "/file/{path}": { + "parameters": [ + { + "name": "path", + "description": "Path of file to rename.", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "path", + "default": "home/nchoquet" + }, + "style": "simple", + "example": "home/nchoquet" + } + ], + "get": { + "summary": "Get selected file content", + "description": "Get selected file content", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Files" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object" + } + }, + "text/xml": { + "schema": { + "type": "string" + } + }, + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/pdf": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "403": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + }, + "patch": { + "summary": "Rename selected file", + "description": "Rename selected file", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Files" + ], + "requestBody": { + "$ref": "#/components/requestBodies/FileSystemItem" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileSystemItem" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + }, + "put": { + "description": "Update file content", + "summary": "Update file content", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Files" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object" + }, + { + "type": "array" + } + ] + } + }, + "text/plain": { + "schema": { + "type": "string" + } + }, + "application/xml": { + "schema": { + "type": "string" + } + }, + "application/pdf": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + }, + "delete": { + "description": "Delete selected file", + "summary": "Delete selected file", + "security": [ + { + "oauth2": [ + "readonly", + "readwrite" + ] + } + ], + "tags": [ + "Files" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResponseStatus" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpError" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/file-system-service.swagger.yml b/swagger/swagger.yaml old mode 100644 new mode 100755 similarity index 86% rename from file-system-service.swagger.yml rename to swagger/swagger.yaml index 5b50784..c5788a4 --- a/file-system-service.swagger.yml +++ b/swagger/swagger.yaml @@ -2,7 +2,7 @@ openapi: '3.0.3' info: title: File system Service - version: 0.10.1 + version: 1.0.0 servers: - url: http://{host}:{port} @@ -14,6 +14,16 @@ servers: description: Port where is exposed service. components: + securitySchemes: + oauth2: + type: oauth2 + flows: + clientCredentials: + tokenUrl: /auth/get-token + scopes: + readwrite: lecture et ecriture + readonly: lecture seule + requestBodies: FileSystemItem: required: true @@ -42,7 +52,7 @@ components: message: type: string - FileSystemItem: + FileSystemItemWithoutExtension: type: object required: - type @@ -60,6 +70,10 @@ components: type: string "symlink": type: string + + FileSystemItemExtension: + type: object + properties: extension: type: string enum: @@ -69,6 +83,35 @@ components: - ".json" - ".xml" + FileSystemItem: + allOf: + - $ref: '#/components/schemas/FileSystemItemWithoutExtension' + - $ref: '#/components/schemas/FileSystemItemExtension' + # required: + # - type + # - path + # - name + # properties: + # type: + # type: string + # enum: + # - "file" + # - "directory" + # path: + # type: string + # name: + # type: string + # "symlink": + # type: string + # extension: + # type: string + # enum: + # - "" + # - ".txt" + # - ".pdf" + # - ".json" + # - ".xml" + ResponseStatus: type: object properties: @@ -89,9 +132,10 @@ components: expires_in: type: integer +security: + - oauth2: ['readonly', 'readwrite'] + tags: - - name: Auth - description: API Authentication - name: File System description: All concerns file system. - name: Files @@ -100,72 +144,6 @@ tags: description: All concerns directories. paths: - /auth/get-token: - post: - tags: - - Auth - description: Create first token - parameters: - - name: Signature-Token - in: header - schema: - type: string - required: true - responses: - '200': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/AccessToken' - '400': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/HttpError' - '500': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/HttpError' - - put: - tags: - - Auth - description: Create new token from refresh token - parameters: - - name: Signature-Token - in: header - schema: - type: string - required: true - - name: Refresh-Token - in: header - schema: - type: string - required: true - responses: - '200': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/AccessToken' - '400': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/HttpError' - '500': - description: Get token - content: - application/json: - schema: - $ref: '#/components/schemas/HttpError' - /check-validity: get: description: New endpoint @@ -194,6 +172,9 @@ paths: example: home/nchoquet get: + security: + - oauth2: ['readonly', 'readwrite'] + tags: - File System @@ -206,7 +187,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/FileSystemItem' + $ref: '#/components/schemas/FileSystemItemWithoutExtension' '400': description: Bad Request @@ -223,12 +204,15 @@ paths: application/json: schema: $ref: '#/components/schemas/HttpError' - - /file-system: + + /file-system/: summary: Get all content of root directory (flat) description: Get all elements in search directory (in root of your system) - + get: + security: + - oauth2: ['readonly', 'readwrite'] + tags: - File System @@ -240,7 +224,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/FileSystemItem' + $ref: '#/components/schemas/FileSystemItemWithoutExtension' '400': description: Bad Request @@ -262,6 +246,9 @@ paths: description: Create new directory post: + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Directories @@ -318,6 +305,9 @@ paths: summary: Rename selected directory description: Rename selected directory + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Directories @@ -361,6 +351,9 @@ paths: summary: Delete a directory description: Delete a directory + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Directories @@ -402,6 +395,9 @@ paths: description: Create new file with or without content post: + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Files @@ -468,6 +464,9 @@ paths: summary: Get selected file content description: Get selected file content + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Files @@ -521,6 +520,9 @@ paths: summary: Rename selected file description: Rename selected file + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Files @@ -556,6 +558,9 @@ paths: description: Update file content summary: Update file content + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Files @@ -609,6 +614,9 @@ paths: description: Delete selected file summary: Delete selected file + security: + - oauth2: ['readonly', 'readwrite'] + tags: - Files diff --git a/types/checkValidity.go b/types/checkValidity.go old mode 100644 new mode 100755 diff --git a/types/httpError.go b/types/httpError.go old mode 100644 new mode 100755 diff --git a/types/responseStatus.go b/types/responseStatus.go old mode 100644 new mode 100755