2020-05-14 19:13:33 -04:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-12-30 09:25:21 -05:00
|
|
|
"embed"
|
2020-05-14 19:13:33 -04:00
|
|
|
"fmt"
|
2023-01-16 06:46:43 -05:00
|
|
|
"io/fs"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
"github.com/flant/ovpn-admin/backend"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
|
|
ou "github.com/pashcovich/openvpn-user/src"
|
2021-07-21 18:06:34 -04:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
2021-12-30 03:24:44 -05:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-07-21 18:06:34 -04:00
|
|
|
"gopkg.in/alecthomas/kingpin.v2"
|
2020-10-15 12:12:31 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2022-12-30 09:25:21 -05:00
|
|
|
version = "2.1.0"
|
2020-11-27 02:23:59 -05:00
|
|
|
)
|
|
|
|
|
2021-12-30 03:24:44 -05:00
|
|
|
var logLevels = map[string]log.Level{
|
2022-01-20 11:42:36 -05:00
|
|
|
"trace": log.TraceLevel,
|
2021-12-30 03:24:44 -05:00
|
|
|
"debug": log.DebugLevel,
|
|
|
|
"info": log.InfoLevel,
|
|
|
|
"warn": log.WarnLevel,
|
|
|
|
"error": log.ErrorLevel,
|
|
|
|
}
|
|
|
|
|
2022-01-20 11:42:36 -05:00
|
|
|
var logFormats = map[string]log.Formatter{
|
|
|
|
"text": &log.TextFormatter{},
|
|
|
|
"json": &log.JSONFormatter{},
|
|
|
|
}
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
//go:embed frontend/static
|
|
|
|
var staticFS embed.FS
|
2021-07-21 18:06:34 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
//go:embed templates
|
|
|
|
var templatesFS embed.FS
|
2021-07-21 18:06:34 -04:00
|
|
|
|
2020-05-14 19:13:33 -04:00
|
|
|
func main() {
|
2021-02-20 07:48:41 -05:00
|
|
|
kingpin.Version(version)
|
|
|
|
kingpin.Parse()
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
log.SetLevel(logLevels[*backend.LogLevel])
|
|
|
|
log.SetFormatter(logFormats[*backend.LogFormat])
|
2021-07-21 18:06:34 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin := new(backend.OvpnAdmin)
|
|
|
|
ovpnAdmin.OUser = new(ou.OpenvpnUser)
|
2020-11-17 12:48:26 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if *backend.StorageBackend == "kubernetes.secrets" {
|
2023-01-16 06:46:43 -05:00
|
|
|
ovpnAdmin.KubeClient = new(backend.OpenVPNPKI)
|
|
|
|
err := ovpnAdmin.KubeClient.Run()
|
2022-08-02 10:19:27 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
2021-07-21 18:06:34 -04:00
|
|
|
}
|
|
|
|
}
|
2020-10-15 12:12:31 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if *backend.IndexTxtPath == "" {
|
|
|
|
*backend.IndexTxtPath = *backend.EasyrsaDirPath + "/pki/index.txt"
|
2021-12-30 03:24:44 -05:00
|
|
|
}
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.LastSyncTime = "unknown"
|
|
|
|
ovpnAdmin.Role = *backend.ServerRole
|
|
|
|
ovpnAdmin.LastSuccessfulSyncTime = "unknown"
|
|
|
|
ovpnAdmin.MasterSyncToken = *backend.MasterSyncToken
|
|
|
|
ovpnAdmin.PromRegistry = prometheus.NewRegistry()
|
|
|
|
ovpnAdmin.Modules = []string{}
|
|
|
|
ovpnAdmin.CreateUserMutex = &sync.Mutex{}
|
|
|
|
ovpnAdmin.MgmtInterfaces = make(map[string]string)
|
2022-01-20 11:42:36 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
for _, mgmtInterface := range *backend.MgmtAddress {
|
|
|
|
parts := strings.SplitN(mgmtInterface, "=", 2)
|
|
|
|
ovpnAdmin.MgmtInterfaces[parts[0]] = parts[len(parts)-1]
|
2022-08-12 06:52:45 -04:00
|
|
|
}
|
2020-05-14 19:13:33 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if *backend.MasterBasicAuthPassword != "" && *backend.MasterBasicAuthUser != "" {
|
|
|
|
ovpnAdmin.MasterHostBasicAuth = true
|
2021-02-15 01:03:38 -05:00
|
|
|
} else {
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.MasterHostBasicAuth = false
|
2020-11-27 02:23:59 -05:00
|
|
|
}
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "core")
|
2020-05-14 19:13:33 -04:00
|
|
|
|
2023-10-06 14:47:28 -04:00
|
|
|
switch *backend.AuthType {
|
|
|
|
case "TOTP":
|
|
|
|
ovpnAdmin.ExtraAuth = true
|
|
|
|
ovpnAdmin.OUser.Database = backend.OpenDB(*backend.AuthDatabase)
|
|
|
|
defer ovpnAdmin.OUser.Database.Close()
|
|
|
|
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "totpAuth")
|
|
|
|
case "PASSWORD":
|
|
|
|
ovpnAdmin.ExtraAuth = true
|
|
|
|
ovpnAdmin.OUser.Database = backend.OpenDB(*backend.AuthDatabase)
|
|
|
|
defer ovpnAdmin.OUser.Database.Close()
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "passwdAuth")
|
2020-05-14 19:13:33 -04:00
|
|
|
}
|
2022-07-21 11:17:53 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if *backend.CcdEnabled {
|
|
|
|
ovpnAdmin.Modules = append(ovpnAdmin.Modules, "ccd")
|
2020-05-14 19:13:33 -04:00
|
|
|
}
|
2022-08-02 10:19:27 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if ovpnAdmin.Role == "slave" {
|
|
|
|
ovpnAdmin.SyncDataFromMaster()
|
|
|
|
go ovpnAdmin.SyncWithMaster()
|
2022-07-21 11:17:53 -04:00
|
|
|
}
|
2020-11-27 02:23:59 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
templatesRoot, err := fs.Sub(templatesFS, "templates")
|
2020-11-17 12:48:26 -05:00
|
|
|
if err != nil {
|
2022-12-30 09:25:21 -05:00
|
|
|
log.Fatal(err)
|
2022-01-20 11:42:36 -05:00
|
|
|
}
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
staticRoot, err := fs.Sub(staticFS, "frontend/static")
|
2021-07-21 18:06:34 -04:00
|
|
|
if err != nil {
|
2022-12-30 09:25:21 -05:00
|
|
|
log.Fatal(err)
|
2020-10-29 06:50:19 -04:00
|
|
|
}
|
2020-11-17 12:48:26 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.Templates = templatesRoot
|
|
|
|
static := CacheControlWrapper(http.FileServer(http.FS(staticRoot)))
|
2020-10-29 06:50:19 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.MgmtSetTimeFormat()
|
2020-10-29 06:50:19 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
ovpnAdmin.RegisterMetrics()
|
|
|
|
ovpnAdmin.SetState()
|
2020-10-29 06:50:19 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
go ovpnAdmin.UpdateState()
|
2020-11-17 12:48:26 -05:00
|
|
|
|
2023-10-09 11:25:23 -04:00
|
|
|
listenBaseUrl := *backend.ListenBaseUrl
|
|
|
|
|
|
|
|
http.Handle(listenBaseUrl, http.StripPrefix(strings.TrimRight(listenBaseUrl, "/"), static))
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/server/settings", ovpnAdmin.ServerSettingsHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/users/list", ovpnAdmin.UserListHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/create", ovpnAdmin.UserCreateHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/rotate", ovpnAdmin.UserRotateHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/delete", ovpnAdmin.UserDeleteHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/revoke", ovpnAdmin.UserRevokeHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/unrevoke", ovpnAdmin.UserUnrevokeHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/config/show", ovpnAdmin.UserShowConfigHandler)
|
|
|
|
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/disconnect", ovpnAdmin.UserDisconnectHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/statistic", ovpnAdmin.UserStatisticHandler)
|
2021-10-05 11:09:29 -04:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
if *backend.CcdEnabled {
|
2023-10-09 11:25:23 -04:00
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/ccd", ovpnAdmin.UserShowCcdHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/ccd/apply", ovpnAdmin.UserApplyCcdHandler)
|
2021-10-05 11:09:29 -04:00
|
|
|
}
|
|
|
|
|
2023-10-06 14:47:28 -04:00
|
|
|
if ovpnAdmin.ExtraAuth {
|
2023-10-09 11:25:23 -04:00
|
|
|
http.HandleFunc(listenBaseUrl + "api/user/change-password", ovpnAdmin.UserChangePasswordHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "/api/auth/check", ovpnAdmin.AuthCheckHandler)
|
2023-10-06 14:47:28 -04:00
|
|
|
if *backend.AuthType == "TOTP" {
|
2023-10-09 11:25:23 -04:00
|
|
|
http.HandleFunc(listenBaseUrl + "/api/user/2fa/secret", ovpnAdmin.UserGetSecretHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "/api/user/2fa/register", ovpnAdmin.UserSetupTFAHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "/api/user/2fa/reset", ovpnAdmin.UserResetTFAHandler)
|
2022-01-20 11:42:36 -05:00
|
|
|
}
|
2022-04-27 06:42:59 -04:00
|
|
|
}
|
2021-10-05 11:09:29 -04:00
|
|
|
|
2023-10-09 11:25:23 -04:00
|
|
|
http.HandleFunc(listenBaseUrl + "/api/sync/last/try", ovpnAdmin.LastSyncTimeHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + "/api/sync/last/successful", ovpnAdmin.LastSuccessfulSyncTimeHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + backend.DownloadCertsApiUrl, ovpnAdmin.DownloadCertsHandler)
|
|
|
|
http.HandleFunc(listenBaseUrl + backend.DownloadCcdApiUrl, ovpnAdmin.DownloadCcdHandler)
|
2022-01-20 09:49:03 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
http.Handle(*backend.MetricsPath, promhttp.HandlerFor(ovpnAdmin.PromRegistry, promhttp.HandlerOpts{}))
|
2023-10-09 11:25:23 -04:00
|
|
|
http.HandleFunc(listenBaseUrl + "/ping", func(w http.ResponseWriter, r *http.Request) {
|
2022-12-30 09:25:21 -05:00
|
|
|
fmt.Fprintf(w, "pong")
|
|
|
|
})
|
2020-11-27 02:23:59 -05:00
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
log.Printf("Bind: http://%s:%s", *backend.ListenHost, *backend.ListenPort)
|
|
|
|
log.Fatal(http.ListenAndServe(*backend.ListenHost+":"+*backend.ListenPort, nil))
|
2020-11-27 02:23:59 -05:00
|
|
|
}
|
|
|
|
|
2022-12-30 09:25:21 -05:00
|
|
|
func CacheControlWrapper(h http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
|
|
|
|
h.ServeHTTP(w, r)
|
|
|
|
})
|
2020-11-27 02:23:59 -05:00
|
|
|
}
|