360 lines
10 KiB
Go
360 lines
10 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"kemendagri/sipd/services/sipd_auth/controller"
|
|
"kemendagri/sipd/services/sipd_auth/handler/http"
|
|
"kemendagri/sipd/services/sipd_auth/handler/http/configs"
|
|
"kemendagri/sipd/services/sipd_auth/handler/http/http_util"
|
|
_deliveryMiddleware "kemendagri/sipd/services/sipd_auth/handler/http/middleware"
|
|
db2 "kemendagri/sipd/services/sipd_auth/model/db"
|
|
"kemendagri/sipd/services/sipd_auth/utils"
|
|
"kemendagri/sipd/services/sipd_auth/utils/captcha_store"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
swagger "github.com/arsmn/fiber-swagger/v2"
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/storage/redis/v3"
|
|
"github.com/golang-migrate/migrate/v4"
|
|
"github.com/golang-migrate/migrate/v4/database"
|
|
_ "github.com/golang-migrate/migrate/v4/source/file"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
_ "github.com/lib/pq"
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/sirupsen/logrus"
|
|
|
|
swagDoc "kemendagri/sipd/services/sipd_auth/docs" // load API Docs files (Swagger)
|
|
)
|
|
|
|
var serverName,
|
|
serverUrl,
|
|
serverReadTimeout,
|
|
dbServerUrl,
|
|
dbServerUrlPegawai,
|
|
dbServerUrlMstData,
|
|
dbServerUrlTransaksi,
|
|
jwtSecertKey,
|
|
jwtExpiredMinutes,
|
|
refreshTokenExpiredHour,
|
|
alwOrg,
|
|
redisHost,
|
|
redisUsername,
|
|
redisPassword,
|
|
urlScheme,
|
|
baseUrl,
|
|
basePath,
|
|
avYear string
|
|
var usedProvArr, avYearArr []string
|
|
|
|
var redisPort int
|
|
|
|
var db *sql.DB
|
|
var pgxConn, pgxConnPegawai, pgxConnMstData *pgxpool.Pool
|
|
var dbConnMapsAnggaran map[string]*pgxpool.Pool
|
|
var driver database.Driver
|
|
var migration *migrate.Migrate
|
|
var jwtMgr *utils.JWTManager
|
|
var vld *validator.Validate
|
|
var minioClient *minio.Client
|
|
var redisCl *redis.Storage
|
|
var logger *logrus.Logger
|
|
var err error
|
|
|
|
func init() {
|
|
// Server Env
|
|
serverName = os.Getenv("SERVER_NAME")
|
|
if serverName == "" {
|
|
exitf("SERVER_NAME env is required")
|
|
}
|
|
serverUrl = os.Getenv("SERVER_URL")
|
|
if serverUrl == "" {
|
|
exitf("SERVER_URL env is required")
|
|
}
|
|
serverReadTimeout = os.Getenv("SERVER_READ_TIMEOUT")
|
|
if serverReadTimeout == "" {
|
|
exitf("SERVER_READ_TIMEOUT env is required")
|
|
}
|
|
|
|
// JWT Env
|
|
jwtSecertKey = os.Getenv("JWT_SECRET_KEY")
|
|
if jwtSecertKey == "" {
|
|
exitf("JWT_SECRET_KEY env is required")
|
|
}
|
|
jwtExpiredMinutes = os.Getenv("JWT_EXPIRED_MINUTES")
|
|
if jwtExpiredMinutes == "" {
|
|
exitf("JWT_EXPIRED_MINUTES env is required")
|
|
}
|
|
refreshTokenExpiredHour = os.Getenv("REFRESH_TOKEN_EXPIRED_HOUR")
|
|
if refreshTokenExpiredHour == "" {
|
|
exitf("REFRESH_TOKEN_EXPIRED_HOUR env is required")
|
|
}
|
|
|
|
// CORS
|
|
alwOrg = os.Getenv("SIPD_CORS_WHITELISTS")
|
|
if alwOrg == "" {
|
|
exitf("SIPD_CORS_WHITELISTS config is required")
|
|
}
|
|
|
|
urlScheme = os.Getenv("URL_SCHEME")
|
|
if urlScheme == "" {
|
|
exitf("URL_SCHEME config is required")
|
|
}
|
|
baseUrl = os.Getenv("BASE_URL")
|
|
if baseUrl == "" {
|
|
exitf("BASE_URL config is required")
|
|
}
|
|
/*basePath = os.Getenv("BASE_PATH")
|
|
if basePath == "" {
|
|
exitf("BASE_PATH config is required")
|
|
}*/
|
|
|
|
avYear = os.Getenv("AVAILABLE_YEAR")
|
|
if avYear == "" {
|
|
exitf("AVAILABLE_YEAR config is required")
|
|
}
|
|
avYearArr = strings.Split(avYear, ",")
|
|
|
|
// Databse Env
|
|
dbServerUrl = os.Getenv("DB_SIPD_AUTH")
|
|
if dbServerUrl == "" {
|
|
exitf("DB_SIPD_AUTH config is required")
|
|
}
|
|
dbServerUrlPegawai = os.Getenv("DB_SIPD_PEGAWAI")
|
|
if dbServerUrlPegawai == "" {
|
|
exitf("DB_SIPD_PEGAWAI config is required")
|
|
}
|
|
dbServerUrlMstData = os.Getenv("DB_SIPD_MST_DATA")
|
|
if dbServerUrlMstData == "" {
|
|
exitf("DB_SIPD_MST_DATA config is required")
|
|
}
|
|
|
|
dbServerUrlTransaksi = os.Getenv("DB_SIPD_TRANSAKSI")
|
|
if dbServerUrlTransaksi == "" {
|
|
exitf("DB_SIPD_TRANSAKSI config is required")
|
|
}
|
|
|
|
var dbConnObj db2.DatabaseConnProv
|
|
err = json.Unmarshal([]byte(dbServerUrlTransaksi), &dbConnObj)
|
|
if err != nil {
|
|
exitf("gagal encode db connection object: %v\n", err)
|
|
}
|
|
|
|
for _, y := range avYearArr {
|
|
yPrefix := "_" + y
|
|
for _, p := range dbConnObj {
|
|
usedProvArr = append(usedProvArr, p.DdnProv+yPrefix)
|
|
|
|
// penganggaran
|
|
err = os.Setenv(
|
|
"DB_SIPD_TRANSAKSI_"+p.DdnProv+yPrefix,
|
|
fmt.Sprintf(
|
|
"host=%s port=%s user=%s password=%s dbname=%s%s sslmode=%s application_name=%s",
|
|
p.Host, p.Port, p.User, p.Password, p.Dbname, yPrefix, p.SslMode, serverName,
|
|
),
|
|
)
|
|
if err != nil {
|
|
exitf("gagal set env (%s) : %v\n", p.DdnProv+yPrefix, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func dbConnection() {
|
|
var maxConnLifetime, maxConnIdleTime time.Duration
|
|
var maxPoolConn int32
|
|
maxConnLifetime = 5 * time.Minute
|
|
maxConnIdleTime = 2 * time.Minute
|
|
maxPoolConn = 1000
|
|
|
|
var cfg, cfgMstData, cfgPegawai *pgxpool.Config
|
|
|
|
// auth
|
|
cfg, err = pgxpool.ParseConfig(dbServerUrl + " application_name=" + serverName)
|
|
if err != nil {
|
|
exitf("Unable to create db pool config auth %v\n", err)
|
|
}
|
|
cfg.MaxConns = maxPoolConn // Maximum total connections in the pool
|
|
cfg.MaxConnLifetime = maxConnLifetime // Maximum lifetime of a connection
|
|
cfg.MaxConnIdleTime = maxConnIdleTime // Maximum time a connection can be idle
|
|
pgxConn, err = pgxpool.NewWithConfig(context.Background(), cfg)
|
|
if err != nil {
|
|
exitf("Unable to connect to database auth: %v\n", err)
|
|
}
|
|
|
|
// pegawai
|
|
cfgPegawai, err = pgxpool.ParseConfig(dbServerUrlPegawai + " application_name=" + serverName)
|
|
if err != nil {
|
|
exitf("Unable to create db pool config pegawai %v\n", err)
|
|
}
|
|
cfgPegawai.MaxConns = maxPoolConn // Maximum total connections in the pool
|
|
cfgPegawai.MaxConnLifetime = maxConnLifetime // Maximum lifetime of a connection
|
|
cfgPegawai.MaxConnIdleTime = maxConnIdleTime // Maximum time a connection can be idle
|
|
pgxConnPegawai, err = pgxpool.NewWithConfig(context.Background(), cfgPegawai)
|
|
if err != nil {
|
|
exitf("Unable to connect to database pegawai: %v\n", err)
|
|
}
|
|
|
|
// mst_data
|
|
cfgMstData, err = pgxpool.ParseConfig(dbServerUrlMstData + " application_name=" + serverName)
|
|
if err != nil {
|
|
exitf("Unable to create db pool config mst_data %v\n", err)
|
|
}
|
|
cfgMstData.MaxConns = maxPoolConn // Maximum total connections in the pool
|
|
cfgMstData.MaxConnLifetime = maxConnLifetime // Maximum lifetime of a connection
|
|
cfgMstData.MaxConnIdleTime = maxConnIdleTime // Maximum time a connection can be idle
|
|
pgxConnMstData, err = pgxpool.NewWithConfig(context.Background(), cfgMstData)
|
|
if err != nil {
|
|
exitf("Unable to connect to database mst_data: %v\n", err)
|
|
}
|
|
|
|
dbConnMapsAnggaran = map[string]*pgxpool.Pool{}
|
|
for _, kodeProv := range usedProvArr {
|
|
// penganggaran
|
|
cfg, err = pgxpool.ParseConfig(os.Getenv("DB_SIPD_TRANSAKSI_"+kodeProv) + " application_name=" + serverName)
|
|
if err != nil {
|
|
exitf("Unable to create db pool config referensi %v\n", err)
|
|
}
|
|
|
|
cfg.MaxConns = maxPoolConn // Maximum total connections in the pool
|
|
cfg.MaxConnLifetime = maxConnLifetime // Maximum lifetime of a connection
|
|
cfg.MaxConnIdleTime = maxConnIdleTime // Maximum time a connection can be idle
|
|
dbConnMapsAnggaran[kodeProv], err = pgxpool.NewWithConfig(context.Background(), cfg)
|
|
if err != nil {
|
|
exitf("Unable to connect to database referensi %s: %v\n", kodeProv, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// @title SIPD Service Auth
|
|
// @version 1.0
|
|
// @description SIPD Service Auth Rest API.
|
|
// @termsOfService http://swagger.io/terms/
|
|
// @contact.name API Support
|
|
// @contact.email lifelinejar@mail.com
|
|
// @license.name Apache 2.0
|
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
|
// @securityDefinitions.apikey ApiKeyAuth
|
|
// @in header
|
|
// @name Authorization
|
|
// @BasePath /auth/
|
|
func main() {
|
|
dbConnection()
|
|
defer func() {
|
|
pgxConn.Close()
|
|
pgxConnMstData.Close()
|
|
}()
|
|
|
|
serverReadTimeoutInt, err := strconv.Atoi(serverReadTimeout)
|
|
if err != nil {
|
|
exitf("Failed casting timeout context: ", err)
|
|
}
|
|
timeoutContext := time.Duration(serverReadTimeoutInt) * time.Second
|
|
|
|
// Define a validator
|
|
vld = utils.NewValidator()
|
|
|
|
// jwt manager
|
|
jwtMgr = utils.NewJWTManager(jwtSecertKey, serverName)
|
|
|
|
swagDoc.SwaggerInfo.Host = "http://localhost"
|
|
swagDoc.SwaggerInfo.BasePath = "/"
|
|
|
|
// Define Fiber config.
|
|
config := configs.FiberConfig()
|
|
app := fiber.New(config)
|
|
|
|
app.Static("/assets", "./assets")
|
|
|
|
// Swagger handler
|
|
//app.Get("/swagger/*", swagger.HandlerDefault)
|
|
swagDoc.SwaggerInfo.Host = baseUrl
|
|
swagDoc.SwaggerInfo.BasePath = basePath
|
|
app.Get("/swagger/*", swagger.New(swagger.Config{
|
|
// URL: urlScheme + baseUrl + basePath + "swagger/doc.json", // default search box
|
|
URL: urlScheme + baseUrl + path.Join(basePath, "swagger/doc.json"),
|
|
}))
|
|
|
|
middL := _deliveryMiddleware.InitMiddleware(app, redisCl, logger)
|
|
//app.Use(middL.RateLimiter())
|
|
app.Use(middL.CORS())
|
|
app.Use(middL.LOGGER())
|
|
//app.Use(middL.RateLimiter())
|
|
app.Use(func(c *fiber.Ctx) error { // Middleware to check for whitelisted domains
|
|
if alwOrg == "*" {
|
|
// Continue to the next middleware/handler
|
|
return c.Next()
|
|
}
|
|
|
|
// Use "X-Forwarded-Host" to simulate the Host header in Postman
|
|
origin := c.Get("Origin")
|
|
// log.Println("Origin: ", origin)
|
|
|
|
alwOrgArr := strings.Split(alwOrg, ",")
|
|
// log.Println("alwOrgArr: ", alwOrgArr)
|
|
|
|
var originMatch bool
|
|
for _, alo := range alwOrgArr {
|
|
if origin == alo {
|
|
originMatch = true
|
|
break
|
|
} else {
|
|
/*host := c.Hostname()
|
|
// log.Println("Host: ", host)
|
|
if "https://"+host == alo || "http://"+host == alo {
|
|
originMatch = true
|
|
break
|
|
}*/
|
|
}
|
|
}
|
|
if !originMatch {
|
|
// log.Println("not match")
|
|
return c.Status(fiber.StatusForbidden).SendString("403 - AU: origin not allowed")
|
|
}
|
|
|
|
// Continue to the next middleware/handler
|
|
return c.Next()
|
|
})
|
|
|
|
http.NewSiteHandler(app, controller.NewSiteController(pgxConn, timeoutContext), vld)
|
|
|
|
captchaStore := captcha_store.NewPostgreSQLStore(pgxConn)
|
|
http.NewCaptchaHandler(app, controller.NewCaptchaController(captchaStore, timeoutContext, vld))
|
|
|
|
authController := controller.NewAuthController(
|
|
pgxConn,
|
|
pgxConnPegawai,
|
|
pgxConnMstData,
|
|
dbConnMapsAnggaran,
|
|
timeoutContext,
|
|
jwtMgr,
|
|
vld,
|
|
)
|
|
http.NewAuthHandler(app, authController, vld)
|
|
|
|
// private router
|
|
rStrict := app.Group("/strict", middL.JWT()) // router for api private access
|
|
userController := controller.NewUserController(pgxConn, pgxConnPegawai, pgxConnMstData, dbConnMapsAnggaran, minioClient, timeoutContext, redisCl)
|
|
http.NewUserHandler(rStrict, vld, userController)
|
|
|
|
// end router
|
|
|
|
http_util.StartServer(app)
|
|
}
|
|
|
|
func exitf(s string, args ...interface{}) {
|
|
errorf(s, args...)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func errorf(s string, args ...interface{}) {
|
|
fmt.Fprintf(os.Stderr, s+"\n", args...)
|
|
}
|