mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-10-31 10:37:13 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			184 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"github.com/otaxhu/problem"
 | |
| 	"github.com/zoriya/kyoo/keibi/dbc"
 | |
| 	_ "github.com/zoriya/kyoo/keibi/docs"
 | |
| 
 | |
| 	"github.com/go-playground/validator/v10"
 | |
| 	"github.com/golang-migrate/migrate/v4"
 | |
| 	pgxd "github.com/golang-migrate/migrate/v4/database/pgx/v5"
 | |
| 	_ "github.com/golang-migrate/migrate/v4/source/file"
 | |
| 	"github.com/jackc/pgx/v5/pgxpool"
 | |
| 	"github.com/jackc/pgx/v5/stdlib"
 | |
| 	"github.com/labstack/echo-jwt/v4"
 | |
| 	"github.com/labstack/echo/v4"
 | |
| 	"github.com/labstack/echo/v4/middleware"
 | |
| 	"github.com/swaggo/echo-swagger"
 | |
| )
 | |
| 
 | |
| func ErrorHandler(err error, c echo.Context) {
 | |
| 	code := http.StatusInternalServerError
 | |
| 	var message string
 | |
| 
 | |
| 	if he, ok := err.(*echo.HTTPError); ok {
 | |
| 		code = he.Code
 | |
| 		message = fmt.Sprint(he.Message)
 | |
| 	} else {
 | |
| 		c.Logger().Error(err)
 | |
| 	}
 | |
| 
 | |
| 	ret := problem.NewDefault(code)
 | |
| 	if message != "" {
 | |
| 		ret.Detail = message
 | |
| 	}
 | |
| 	c.JSON(code, ret)
 | |
| }
 | |
| 
 | |
| type Validator struct {
 | |
| 	validator *validator.Validate
 | |
| }
 | |
| 
 | |
| func (v *Validator) Validate(i interface{}) error {
 | |
| 	if err := v.validator.Struct(i); err != nil {
 | |
| 		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func OpenDatabase() (*pgxpool.Pool, error) {
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	port, err := strconv.ParseUint(os.Getenv("POSTGRES_PORT"), 10, 16)
 | |
| 	if err != nil {
 | |
| 		return nil, errors.New("invalid postgres port specified")
 | |
| 	}
 | |
| 
 | |
| 	config, _ := pgxpool.ParseConfig("")
 | |
| 	config.ConnConfig.Host = os.Getenv("POSTGRES_SERVER")
 | |
| 	config.ConnConfig.Port = uint16(port)
 | |
| 	config.ConnConfig.Database = os.Getenv("POSTGRES_DB")
 | |
| 	config.ConnConfig.User = os.Getenv("POSTGRES_USER")
 | |
| 	config.ConnConfig.Password = os.Getenv("POSTGRES_PASSWORD")
 | |
| 	config.ConnConfig.TLSConfig = nil
 | |
| 	config.ConnConfig.RuntimeParams = map[string]string{
 | |
| 		"application_name": "keibi",
 | |
| 	}
 | |
| 	schema := os.Getenv("POSTGRES_SCHEMA")
 | |
| 	if schema == "" {
 | |
| 		schema = "keibi"
 | |
| 	}
 | |
| 	if schema != "disabled" {
 | |
| 		config.ConnConfig.RuntimeParams["search_path"] = schema
 | |
| 	}
 | |
| 
 | |
| 	db, err := pgxpool.NewWithConfig(ctx, config)
 | |
| 	if err != nil {
 | |
| 		fmt.Printf("Could not connect to database, check your env variables!")
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if schema != "disabled" {
 | |
| 		_, err = db.Exec(ctx, fmt.Sprintf("create schema if not exists %s", schema))
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("Migrating database")
 | |
| 	dbi := stdlib.OpenDBFromPool(db)
 | |
| 	defer dbi.Close()
 | |
| 
 | |
| 	driver, err := pgxd.WithInstance(dbi, &pgxd.Config{})
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	m, err := migrate.NewWithDatabaseInstance("file://sql/migrations", "postgres", driver)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	m.Up()
 | |
| 	fmt.Println("Migrating finished")
 | |
| 
 | |
| 	return db, nil
 | |
| }
 | |
| 
 | |
| type Handler struct {
 | |
| 	db     *dbc.Queries
 | |
| 	config *Configuration
 | |
| }
 | |
| 
 | |
| // @title Keibi - Kyoo's auth
 | |
| // @version 1.0
 | |
| // @description Auth system made for kyoo.
 | |
| 
 | |
| // @contact.name Repository
 | |
| // @contact.url https://github.com/zoriya/kyoo
 | |
| 
 | |
| // @license.name  GPL-3.0
 | |
| // @license.url https://www.gnu.org/licenses/gpl-3.0.en.html
 | |
| 
 | |
| // @host kyoo.zoriya.dev
 | |
| // @BasePath /auth
 | |
| 
 | |
| // @securityDefinitions.apiKey Token
 | |
| // @in header
 | |
| // @name Authorization
 | |
| 
 | |
| // @securityDefinitions.apiKey Jwt
 | |
| // @in header
 | |
| // @name Authorization
 | |
| func main() {
 | |
| 	e := echo.New()
 | |
| 	e.Use(middleware.Logger())
 | |
| 	e.Validator = &Validator{validator: validator.New(validator.WithRequiredStructEnabled())}
 | |
| 	e.HTTPErrorHandler = ErrorHandler
 | |
| 
 | |
| 	db, err := OpenDatabase()
 | |
| 	if err != nil {
 | |
| 		e.Logger.Fatal("Could not open databse: ", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	h := Handler{
 | |
| 		db: dbc.New(db),
 | |
| 	}
 | |
| 	conf, err := LoadConfiguration(h.db)
 | |
| 	if err != nil {
 | |
| 		e.Logger.Fatal("Could not load configuration: ", err)
 | |
| 		return
 | |
| 	}
 | |
| 	h.config = conf
 | |
| 
 | |
| 	r := e.Group("")
 | |
| 	r.Use(echojwt.WithConfig(echojwt.Config{
 | |
| 		SigningMethod: "RS256",
 | |
| 		SigningKey: h.config.JwtPublicKey,
 | |
| 	}))
 | |
| 
 | |
| 	r.GET("/users", h.ListUsers)
 | |
| 	r.GET("/users/:id", h.GetUser)
 | |
| 	r.GET("/users/me", h.GetMe)
 | |
| 	r.DELETE("/users/:id", h.DeleteUser)
 | |
| 	r.DELETE("/users/me", h.DeleteSelf)
 | |
| 	e.POST("/users", h.Register)
 | |
| 
 | |
| 	e.POST("/sessions", h.Login)
 | |
| 	r.DELETE("/sessions", h.Logout)
 | |
| 	r.DELETE("/sessions/:id", h.Logout)
 | |
| 
 | |
| 	e.GET("/jwt", h.CreateJwt)
 | |
| 	e.GET("/info", h.GetInfo)
 | |
| 
 | |
| 	e.GET("/swagger/*", echoSwagger.WrapHandler)
 | |
| 
 | |
| 	e.Logger.Fatal(e.Start(":4568"))
 | |
| }
 |