WIP Ajouter config.Config et commencer à l'implanter

This commit is contained in:
Victor Lacasse-Beaudoin 2023-07-04 16:05:23 -04:00
parent 64c91b3aeb
commit da42387211
2 changed files with 58 additions and 84 deletions

View file

@ -12,6 +12,8 @@ ADD cmd/ cmd/
ADD api/ api/ ADD api/ api/
Add config/ config/
RUN CGO_ENABLED=0 go build -a -installsuffix cgo -o agecem-org . RUN CGO_ENABLED=0 go build -a -installsuffix cgo -o agecem-org .
# Alpine # Alpine

View file

@ -23,6 +23,7 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
"git.agecem.com/agecem/agecem-org/api" "git.agecem.com/agecem/agecem-org/api"
"git.agecem.com/agecem/agecem-org/config"
"git.agecem.com/agecem/agecem-org/public" "git.agecem.com/agecem/agecem-org/public"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
@ -32,6 +33,8 @@ type Template struct {
templates *template.Template templates *template.Template
} }
var cfg config.Config
var embedFS embed.FS var embedFS embed.FS
// serverCmd represents the server command // serverCmd represents the server command
@ -39,6 +42,10 @@ var serverCmd = &cobra.Command{
Use: "server", Use: "server",
Short: "Démarrer le serveur web", Short: "Démarrer le serveur web",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if err := viper.Unmarshal(&cfg); err != nil {
log.Fatal(err)
}
RunServer() RunServer()
}, },
} }
@ -64,7 +71,7 @@ func init() {
// server.documents.access_key_id - --server-documents-access-key-id // server.documents.access_key_id - --server-documents-access-key-id
serverCmd.Flags().String("server-documents-access-key-id", "", "Storage server access key id (config: server.documents.access_key_id)") serverCmd.Flags().String("server-documents-access-key-id", "", "Storage server access key id (config: server.documents.access_key_id)")
viper.BindPFlag("documents.accessKeyID", serverCmd.Flags().Lookup("documents-access-key-id")) viper.BindPFlag("server.documents.access_key_id", serverCmd.Flags().Lookup("server-documents-access-key-id"))
// server.documents.secret_access_key - --server-documents-secret-access-key // server.documents.secret_access_key - --server-documents-secret-access-key
serverCmd.Flags().String("server-documents-secret-access-key", "", "Storage server secret access key (config: server.documents.secret_access_key)") serverCmd.Flags().String("server-documents-secret-access-key", "", "Storage server secret access key (config: server.documents.secret_access_key)")
@ -114,13 +121,13 @@ func RunServer() {
groupV1.Use(middleware.AddTrailingSlash()) groupV1.Use(middleware.AddTrailingSlash())
if viper.GetBool("server.api.auth") { if cfg.Server.Api.Auth {
if len(viper.GetString("server.api.key")) < 10 { if len(cfg.Server.Api.Key) < 10 {
log.Fatal("server.api.auth is enabled, but server.api.key is too small (needs at least 10 characters)") log.Fatal("server.api.auth is enabled, but server.api.key is too small (needs at least 10 characters)")
} }
groupV1.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) { groupV1.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
return subtle.ConstantTimeCompare([]byte(key), []byte(viper.GetString("server.api.key"))) == 1, nil return subtle.ConstantTimeCompare([]byte(key), []byte(cfg.Server.Api.Key)) == 1, nil
})) }))
log.Println("Key auth for /v1 activated") log.Println("Key auth for /v1 activated")
@ -130,21 +137,19 @@ func RunServer() {
groupAdmin.Use(middleware.AddTrailingSlash()) groupAdmin.Use(middleware.AddTrailingSlash())
if viper.GetBool("server.admin.auth") { if cfg.Server.Admin.Auth {
username := viper.GetString("server.admin.username") if len(cfg.Server.Admin.Username) < 5 {
password := viper.GetString("server.admin.password")
if len(username) < 5 {
log.Fatal("server.admin.auth is enabled, but server.admin.username is too small (needs at least 5 characters)") log.Fatal("server.admin.auth is enabled, but server.admin.username is too small (needs at least 5 characters)")
} }
if len(password) < 10 { if len(cfg.Server.Admin.Password) < 10 {
log.Fatal("server.admin.auth is enabled, but server.admin.password is too small (needs at least 10 characters)") log.Fatal("server.admin.auth is enabled, but server.admin.password is too small (needs at least 10 characters)")
} }
groupAdmin.Use(middleware.BasicAuth(func(username_entered, password_entered string, c echo.Context) (bool, error) { groupAdmin.Use(middleware.BasicAuth(func(username_entered, password_entered string, c echo.Context) (bool, error) {
// Be careful to use constant time comparison to prevent timing attacks // Be careful to use constant time comparison to prevent timing attacks
if subtle.ConstantTimeCompare([]byte(username_entered), []byte(username)) == 1 && if subtle.ConstantTimeCompare([]byte(username_entered), []byte(cfg.Server.Admin.Username)) == 1 &&
subtle.ConstantTimeCompare([]byte(password_entered), []byte(password)) == 1 { subtle.ConstantTimeCompare([]byte(password_entered), []byte(cfg.Server.Admin.Password)) == 1 {
return true, nil return true, nil
} }
return false, nil return false, nil
@ -208,7 +213,7 @@ func RunServer() {
groupAdmin.POST("/documents/upload", handleAdminDocumentsUploadPOST) groupAdmin.POST("/documents/upload", handleAdminDocumentsUploadPOST)
e.Logger.Fatal(e.Start( e.Logger.Fatal(e.Start(
fmt.Sprintf(":%d", viper.GetInt("server.port")))) fmt.Sprintf(":%d", cfg.Server.Port)))
} }
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error { func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
@ -228,30 +233,26 @@ func handleV1(c echo.Context) error {
// handleV1Seed créé des buckets dans minio selon la liste de buckets dans server.documents.buckets // handleV1Seed créé des buckets dans minio selon la liste de buckets dans server.documents.buckets
// Les buckets sont créés avec paramètres par défaut, et sont ensuite visible dans /v1/bucket. // Les buckets sont créés avec paramètres par défaut, et sont ensuite visible dans /v1/bucket.
func handleV1Seed(c echo.Context) error { func handleV1Seed(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "Error during minio#New", "message": "Error during minio#New",
"error": err.Error(),
}) })
} }
var new_buckets []string var new_buckets []string
for _, bucket := range documents_buckets { for _, bucket := range cfg.Server.Documents.Buckets {
exists, err := client.BucketExists(context.Background(), bucket) exists, err := client.BucketExists(context.Background(), bucket)
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "Error during minio#BucketExists", "message": "Error during minio#BucketExists",
"error": err.Error(),
}) })
} }
@ -262,6 +263,7 @@ func handleV1Seed(c echo.Context) error {
if err = client.MakeBucket(context.Background(), bucket, minio.MakeBucketOptions{}); err != nil { if err = client.MakeBucket(context.Background(), bucket, minio.MakeBucketOptions{}); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "Error during minio#MakeBucket", "message": "Error during minio#MakeBucket",
"error": err.Error(),
}) })
} }
new_buckets = append(new_buckets, bucket) new_buckets = append(new_buckets, bucket)
@ -282,16 +284,10 @@ func handleV1Seed(c echo.Context) error {
// handleV1BucketList affiche les buckets permis par server.documents.buckets, qui existent. // handleV1BucketList affiche les buckets permis par server.documents.buckets, qui existent.
func handleV1BucketList(c echo.Context) error { func handleV1BucketList(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
@ -301,7 +297,7 @@ func handleV1BucketList(c echo.Context) error {
var buckets []string var buckets []string
for _, bucket_name := range documents_buckets { for _, bucket_name := range cfg.Server.Documents.Buckets {
exists, err := client.BucketExists(context.Background(), bucket_name) exists, err := client.BucketExists(context.Background(), bucket_name)
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists") return c.JSON(http.StatusInternalServerError, "Error during minio#BucketExists")
@ -316,16 +312,10 @@ func handleV1BucketList(c echo.Context) error {
} }
func handleV1BucketRead(c echo.Context) error { func handleV1BucketRead(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
bucket := c.Param("bucket") bucket := c.Param("bucket")
allowed := false allowed := false
for _, bucket_allowed := range documents_buckets { for _, bucket_allowed := range cfg.Server.Documents.Buckets {
if bucket == bucket_allowed { if bucket == bucket_allowed {
allowed = true allowed = true
} }
@ -345,9 +335,9 @@ func handleV1BucketRead(c echo.Context) error {
defer cancel() defer cancel()
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
@ -382,12 +372,6 @@ func handleV1BucketRead(c echo.Context) error {
// handleV1DocumentCreate permet d'ajouter un object dans un bucket, par multipart/form-data // handleV1DocumentCreate permet d'ajouter un object dans un bucket, par multipart/form-data
func handleV1DocumentCreate(c echo.Context) error { func handleV1DocumentCreate(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
bucket := c.Param("bucket") bucket := c.Param("bucket")
form_file, err := c.FormFile("document") form_file, err := c.FormFile("document")
@ -399,7 +383,7 @@ func handleV1DocumentCreate(c echo.Context) error {
} }
allowed := false allowed := false
for _, bucket_allowed := range documents_buckets { for _, bucket_allowed := range cfg.Server.Documents.Buckets {
if bucket == bucket_allowed { if bucket == bucket_allowed {
allowed = true allowed = true
} }
@ -414,9 +398,9 @@ func handleV1DocumentCreate(c echo.Context) error {
defer cancel() defer cancel()
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
@ -458,17 +442,11 @@ func handleV1DocumentCreate(c echo.Context) error {
// handleV1DocumentRead permet de lire le contenu d'un fichier et protentiellement de le télécharger // handleV1DocumentRead permet de lire le contenu d'un fichier et protentiellement de le télécharger
func handleV1DocumentRead(c echo.Context) error { func handleV1DocumentRead(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
bucket := c.Param("bucket") bucket := c.Param("bucket")
document := c.Param("document") document := c.Param("document")
allowed := false allowed := false
for _, bucket_allowed := range documents_buckets { for _, bucket_allowed := range cfg.Server.Documents.Buckets {
if bucket == bucket_allowed { if bucket == bucket_allowed {
allowed = true allowed = true
} }
@ -488,9 +466,9 @@ func handleV1DocumentRead(c echo.Context) error {
defer cancel() defer cancel()
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
@ -543,17 +521,11 @@ func handleV1DocumentUpdate(c echo.Context) error {
// handleV1DocumentDelete permet de supprimer un object // handleV1DocumentDelete permet de supprimer un object
func handleV1DocumentDelete(c echo.Context) error { func handleV1DocumentDelete(c echo.Context) error {
documents_buckets := viper.GetStringSlice("server.documents.buckets")
documents_endpoint := viper.GetString("server.documents.endpoint")
documents_access_key_id := viper.GetString("server.documents.access_key_id")
documents_secret_access_key := viper.GetString("server.documents.secret_access_key")
documents_use_ssl := viper.GetBool("server.documents.use_ssl")
bucket := c.Param("bucket") bucket := c.Param("bucket")
document := c.Param("document") document := c.Param("document")
allowed := false allowed := false
for _, bucket_allowed := range documents_buckets { for _, bucket_allowed := range cfg.Server.Documents.Buckets {
if bucket == bucket_allowed { if bucket == bucket_allowed {
allowed = true allowed = true
} }
@ -573,9 +545,9 @@ func handleV1DocumentDelete(c echo.Context) error {
defer cancel() defer cancel()
// Initialize minio client object // Initialize minio client object
client, err := minio.New(documents_endpoint, &minio.Options{ client, err := minio.New(cfg.Server.Documents.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(documents_access_key_id, documents_secret_access_key, ""), Creds: credentials.NewStaticV4(cfg.Server.Documents.AccessKeyId, cfg.Server.Documents.SecretAccessKey, ""),
Secure: documents_use_ssl, Secure: cfg.Server.Documents.UseSSL,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{ return c.JSON(http.StatusInternalServerError, map[string]string{
@ -648,9 +620,9 @@ func handleVieEtudianteOrganisme(c echo.Context) error {
} }
func handleDocumentation(c echo.Context) error { func handleDocumentation(c echo.Context) error {
client, err := api.New("http", "localhost", viper.GetInt("server.port"), api.APIOptions{ client, err := api.New("http", "localhost", cfg.Server.Port, api.APIOptions{
KeyAuth: viper.GetBool("server.api.auth"), KeyAuth: cfg.Server.Api.Auth,
Key: viper.GetString("server.api.key"), Key: cfg.Server.Api.Key,
}) })
if err != nil { if err != nil {
return c.Render(http.StatusInternalServerError, "documentation-html", nil) return c.Render(http.StatusInternalServerError, "documentation-html", nil)
@ -720,9 +692,9 @@ func handleFormulaires(c echo.Context) error {
} }
func handlePublicDocumentation(c echo.Context) error { func handlePublicDocumentation(c echo.Context) error {
client, err := api.New("http", "localhost", viper.GetInt("server.port"), api.APIOptions{ client, err := api.New("http", "localhost", cfg.Server.Port, api.APIOptions{
KeyAuth: viper.GetBool("server.api.auth"), KeyAuth: cfg.Server.Api.Auth,
Key: viper.GetString("server.api.key"), Key: cfg.Server.Api.Key,
}) })
if err != nil { if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"}) return c.JSON(http.StatusNotFound, map[string]string{"message": "Not Found"})
@ -756,12 +728,12 @@ func handleAdminDocumentsUpload(c echo.Context) error {
} }
func handleAdminDocumentsUploadPOST(c echo.Context) error { func handleAdminDocumentsUploadPOST(c echo.Context) error {
client, err := api.New("http", "localhost", viper.GetInt("server.port"), api.APIOptions{ client, err := api.New("http", "localhost", cfg.Server.Port, api.APIOptions{
KeyAuth: viper.GetBool("server.api.auth"), KeyAuth: cfg.Server.Api.Auth,
Key: viper.GetString("server.api.key"), Key: cfg.Server.Api.Key,
BasicAuth: viper.GetBool("server.admin.auth"), BasicAuth: cfg.Server.Admin.Auth,
Username: viper.GetString("server.admin.username"), Username: cfg.Server.Admin.Username,
Password: viper.GetString("server.admin.password"), Password: cfg.Server.Admin.Password,
}) })
if err != nil { if err != nil {
return c.Render(http.StatusInternalServerError, "admin-upload-html", struct{ Message string }{Message: fmt.Sprintf("handleAdminDocumentsUploadPOST#api.New: %s", err)}) return c.Render(http.StatusInternalServerError, "admin-upload-html", struct{ Message string }{Message: fmt.Sprintf("handleAdminDocumentsUploadPOST#api.New: %s", err)})