From 633ad79d6a822c347fb47c0750c3a82e3246b784 Mon Sep 17 00:00:00 2001 From: strnk Date: Tue, 7 Dec 2021 15:44:52 +0100 Subject: [PATCH 01/20] Add base URL configuration to the webserver to support reverse-proxy setups --- README.md | 3 +++ main.go | 38 ++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 67344ca..2069316 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ Flags: --listen.port="8080" port for ovpn-admin (or $OVPN_LISTEN_PROT) + --listen.base-url="/" base URL for ovpn-admin web files + (or $OVPN_LISTEN_BASE_URL) + --role="master" server role, master or slave (or $OVPN_ROLE) diff --git a/main.go b/main.go index 327b14b..5dcaadb 100644 --- a/main.go +++ b/main.go @@ -31,8 +31,6 @@ const ( usernameRegexp = `^([a-zA-Z0-9_.-@])+$` passwordRegexp = `^([a-zA-Z0-9_.-@])+$` passwordMinLength = 6 - downloadCertsApiUrl = "/api/data/certs/download" - downloadCcdApiUrl = "/api/data/ccd/download" certsArchiveFileName = "certs.tar.gz" ccdArchiveFileName = "ccd.tar.gz" indexTxtDateLayout = "060102150405Z" @@ -46,6 +44,7 @@ const ( var ( listenHost = kingpin.Flag("listen.host","host for ovpn-admin").Default("0.0.0.0").Envar("OVPN_LISTEN_HOST").String() listenPort = kingpin.Flag("listen.port","port for ovpn-admin").Default("8080").Envar("OVPN_LISTEN_PORT").String() + listenBaseUrl = kingpin.Flag("listen.base-url", "base url for ovpn-admin").Default("/").Envar("OVPN_LISTEN_BASE_URL").String() serverRole = kingpin.Flag("role","server role, master or slave").Default("master").Envar("OVPN_ROLE").HintOptions("master", "slave").String() masterHost = kingpin.Flag("master.host","URL for the master server").Default("http://127.0.0.1").Envar("OVPN_MASTER_HOST").String() masterBasicAuthUser = kingpin.Flag("master.basic-auth.user","user for master server's Basic Auth").Default("").Envar("OVPN_MASTER_USER").String() @@ -69,6 +68,9 @@ var ( debug = kingpin.Flag("debug", "enable debug mode").Default("false").Envar("OVPN_DEBUG").Bool() verbose = kingpin.Flag("verbose", "enable verbose mode").Default("false").Envar("OVPN_VERBOSE").Bool() + downloadCertsApiUrl = *listenBaseUrl + "api/data/certs/download" + downloadCcdApiUrl = *listenBaseUrl + "api/data/ccd/download" + certsArchivePath = "/tmp/" + certsArchiveFileName ccdArchivePath = "/tmp/" + ccdArchiveFileName @@ -443,30 +445,30 @@ func main() { staticBox := packr.New("static", "./frontend/static") static := CacheControlWrapper(http.FileServer(staticBox)) - http.Handle("/", static) - http.HandleFunc("/api/server/settings", ovpnAdmin.serverSettingsHandler) - http.HandleFunc("/api/users/list", ovpnAdmin.userListHandler) - http.HandleFunc("/api/user/create", ovpnAdmin.userCreateHandler) - http.HandleFunc("/api/user/change-password", ovpnAdmin.userChangePasswordHandler) - http.HandleFunc("/api/user/revoke", ovpnAdmin.userRevokeHandler) - http.HandleFunc("/api/user/unrevoke", ovpnAdmin.userUnrevokeHandler) - http.HandleFunc("/api/user/config/show", ovpnAdmin.userShowConfigHandler) - http.HandleFunc("/api/user/disconnect", ovpnAdmin.userDisconnectHandler) - http.HandleFunc("/api/user/statistic", ovpnAdmin.userStatisticHandler) - http.HandleFunc("/api/user/ccd", ovpnAdmin.userShowCcdHandler) - http.HandleFunc("/api/user/ccd/apply", ovpnAdmin.userApplyCcdHandler) + 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/change-password", ovpnAdmin.userChangePasswordHandler) + 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) + http.HandleFunc(*listenBaseUrl + "api/user/ccd", ovpnAdmin.userShowCcdHandler) + http.HandleFunc(*listenBaseUrl + "api/user/ccd/apply", ovpnAdmin.userApplyCcdHandler) - http.HandleFunc("/api/sync/last/try", ovpnAdmin.lastSyncTimeHandler) - http.HandleFunc("/api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler) + http.HandleFunc(*listenBaseUrl + "api/sync/last/try", ovpnAdmin.lastSyncTimeHandler) + http.HandleFunc(*listenBaseUrl + "api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler) http.HandleFunc(downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler) http.HandleFunc(downloadCcdApiUrl, ovpnAdmin.downloadCcdHandler) http.Handle(*metricsPath, promhttp.HandlerFor(ovpnAdmin.promRegistry, promhttp.HandlerOpts{})) - http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { + http.HandleFunc(*listenBaseUrl + "ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "pong") }) - log.Printf("Bind: http://%s:%s\n", *listenHost, *listenPort) + log.Printf("Bind: http://%s:%s%s\n", *listenHost, *listenPort, *listenBaseUrl) log.Fatal(http.ListenAndServe(*listenHost+":"+*listenPort, nil)) } From f73626dd7b05cca9433fc7a28ce1c03b005e67f8 Mon Sep 17 00:00:00 2001 From: strnk Date: Tue, 7 Dec 2021 15:57:31 +0100 Subject: [PATCH 02/20] Add configuration parameter for the easyrsa script path --- main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 5dcaadb..971a8b4 100644 --- a/main.go +++ b/main.go @@ -59,6 +59,7 @@ var ( metricsPath = kingpin.Flag("metrics.path", "URL path for exposing collected metrics").Default("/metrics").Envar("OVPN_METRICS_PATH").String() easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa/").Envar("EASYRSA_PATH").String() indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file").Default("./easyrsa/pki/index.txt").Envar("OVPN_INDEX_PATH").String() + easyrsaBinPath = kingpin.Flag("easyrsa.bin-path", "path to easyrsa script").Default("easyrsa").Envar("EASYRSA_BIN_PATH").String() ccdEnabled = kingpin.Flag("ccd", "enable client-config-dir").Default("false").Envar("OVPN_CCD").Bool() ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").Envar("OVPN_CCD_PATH").String() clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").Envar("OVPN_TEMPLATES_CC_PATH").String() @@ -850,7 +851,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) { } } - o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && easyrsa build-client-full %s nopass", *easyrsaDirPath, username)) + o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && %s build-client-full %s nopass", *easyrsaDirPath, *easyrsaBinPath, username)) log.Println(o) if *authByPassword { @@ -911,7 +912,7 @@ func (oAdmin *OvpnAdmin) getUserStatistic(username string) clientStatus { func (oAdmin *OvpnAdmin) userRevoke(username string) string { if checkUserExist(username) { // check certificate valid flag 'V' - o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && echo yes | easyrsa revoke %s && easyrsa gen-crl", *easyrsaDirPath, username)) + o := runBash(fmt.Sprintf("date +%%Y-%%m-%%d\\ %%H:%%M:%%S && cd %s && echo yes | %s revoke %s && %s gen-crl", *easyrsaDirPath, *easyrsaBinPath, username, *easyrsaBinPath)) if *authByPassword { o = runBash(fmt.Sprintf("openvpn-user revoke --db-path %s --user %s", *authDatabase, username)) //fmt.Println(o) @@ -949,7 +950,7 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) string { //fmt.Println(o) fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt)) //fmt.Print(renderIndexTxt(usersFromIndexTxt)) - o = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl", *easyrsaDirPath)) + o = runBash(fmt.Sprintf("cd %s && %s gen-crl", *easyrsaDirPath, *easyrsaBinPath)) //fmt.Println(o) if *authByPassword { o = runBash(fmt.Sprintf("openvpn-user restore --db-path %s --user %s", *authDatabase, username)) From 0ee9be5744cb397917b217aacedd90c395e3dcae Mon Sep 17 00:00:00 2001 From: strnk Date: Tue, 7 Dec 2021 16:12:57 +0100 Subject: [PATCH 03/20] Fix certs and ccd slave download API endpoints --- main.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 971a8b4..043c940 100644 --- a/main.go +++ b/main.go @@ -36,6 +36,8 @@ const ( indexTxtDateLayout = "060102150405Z" stringDateFormat = "2006-01-02 15:04:05" ovpnStatusDateLayout = "2006-01-02 15:04:05" + downloadCertsApiUrl = "api/data/certs/download" + downloadCcdApiUrl = "api/data/ccd/download" kubeTokenFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/token" kubeNamespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" @@ -69,15 +71,15 @@ var ( debug = kingpin.Flag("debug", "enable debug mode").Default("false").Envar("OVPN_DEBUG").Bool() verbose = kingpin.Flag("verbose", "enable verbose mode").Default("false").Envar("OVPN_VERBOSE").Bool() - downloadCertsApiUrl = *listenBaseUrl + "api/data/certs/download" - downloadCcdApiUrl = *listenBaseUrl + "api/data/ccd/download" - certsArchivePath = "/tmp/" + certsArchiveFileName ccdArchivePath = "/tmp/" + ccdArchiveFileName version = "1.7.5" ) +var ( +) + var ( ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ovpn_server_cert_expire", @@ -461,8 +463,8 @@ func main() { http.HandleFunc(*listenBaseUrl + "api/sync/last/try", ovpnAdmin.lastSyncTimeHandler) http.HandleFunc(*listenBaseUrl + "api/sync/last/successful", ovpnAdmin.lastSuccessfulSyncTimeHandler) - http.HandleFunc(downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler) - http.HandleFunc(downloadCcdApiUrl, ovpnAdmin.downloadCcdHandler) + http.HandleFunc(*listenBaseUrl + downloadCertsApiUrl, ovpnAdmin.downloadCertsHandler) + http.HandleFunc(*listenBaseUrl + downloadCcdApiUrl, ovpnAdmin.downloadCcdHandler) http.Handle(*metricsPath, promhttp.HandlerFor(ovpnAdmin.promRegistry, promhttp.HandlerOpts{})) http.HandleFunc(*listenBaseUrl + "ping", func(w http.ResponseWriter, r *http.Request) { @@ -1076,7 +1078,7 @@ func (oAdmin *OvpnAdmin) downloadCerts() bool { if fExist(certsArchivePath) { fDelete(certsArchivePath) } - err := fDownload(certsArchivePath, *masterHost+downloadCertsApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth) + err := fDownload(certsArchivePath, *masterHost+*listenBaseUrl+downloadCertsApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth) if err != nil { log.Println(err) return false @@ -1090,7 +1092,7 @@ func (oAdmin *OvpnAdmin) downloadCcd() bool { fDelete(ccdArchivePath) } - err := fDownload(ccdArchivePath, *masterHost+downloadCcdApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth) + err := fDownload(ccdArchivePath, *masterHost+*listenBaseUrl+downloadCcdApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth) if err != nil { log.Println(err) return false From 4981dcb9197c3b3229fcafff4597afacb17cb2a8 Mon Sep 17 00:00:00 2001 From: Sprait Date: Mon, 4 Sep 2023 19:24:13 +0300 Subject: [PATCH 04/20] Multi-platform build (#234) * add multi-platform build --- .github/workflows/publish-latest.yaml | 29 ++++++++++++++++----------- .github/workflows/publish-tag.yaml | 29 ++++++++++++++++----------- Dockerfile | 9 ++++++--- Dockerfile.openvpn | 6 ++++-- main.go | 3 --- 5 files changed, 44 insertions(+), 32 deletions(-) diff --git a/.github/workflows/publish-latest.yaml b/.github/workflows/publish-latest.yaml index ff592ba..33cd3cc 100644 --- a/.github/workflows/publish-latest.yaml +++ b/.github/workflows/publish-latest.yaml @@ -12,19 +12,24 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} - name: Push openvpn image to Docker Hub - uses: docker/build-push-action@v1 + uses: docker/build-push-action@v4 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - repository: flant/ovpn-admin - tags: openvpn-latest - dockerfile: Dockerfile.openvpn + tags: flant/ovpn-admin:openvpn-latest + platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + file: Dockerfile.openvpn + push: true - name: Push ovpn-admin image to Docker Hub - uses: docker/build-push-action@v1 + uses: docker/build-push-action@v4 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - repository: flant/ovpn-admin - tags: latest - dockerfile: Dockerfile + tags: flant/ovpn-admin:latest + platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + file: Dockerfile + push: true \ No newline at end of file diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 05eb739..222b30f 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -16,19 +16,24 @@ jobs: - name: Get the version id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} - name: Push openvpn image to Docker Hub - uses: docker/build-push-action@v1 + uses: docker/build-push-action@v4 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - repository: flant/ovpn-admin - tags: openvpn-${{ steps.get_version.outputs.VERSION }} - dockerfile: Dockerfile.openvpn + tags: flant/ovpn-admin:openvpn-${{ steps.get_version.outputs.VERSION }} + platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + file: Dockerfile.openvpn + push: true - name: Push ovpn-admin image to Docker Hub - uses: docker/build-push-action@v1 + uses: docker/build-push-action@v4 with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - repository: flant/ovpn-admin - tags: ${{ steps.get_version.outputs.VERSION }} - dockerfile: Dockerfile + tags: flant/ovpn-admin:${{ steps.get_version.outputs.VERSION }} + platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + file: Dockerfile + push: true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 42ff620..aac416c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,20 @@ FROM node:16-alpine3.15 AS frontend-builder COPY frontend/ /app -RUN cd /app && npm install && npm run build +RUN apk add --update python3 make g++ && cd /app && npm install && npm run build FROM golang:1.17.3-buster AS backend-builder RUN go install github.com/gobuffalo/packr/v2/packr2@latest COPY --from=frontend-builder /app/static /app/frontend/static COPY . /app -RUN cd /app && packr2 && env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin && packr2 clean +ARG TARGETARCH +RUN cd /app && packr2 && env CGO_ENABLED=1 GOOS=linux GOARCH=${TARGETARCH} go build -a -tags netgo -ldflags '-linkmode external -extldflags -static -s -w' -o ovpn-admin && packr2 clean FROM alpine:3.16 WORKDIR /app COPY --from=backend-builder /app/ovpn-admin /app +ARG TARGETARCH RUN apk add --update bash easy-rsa openssl openvpn coreutils && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ - wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.4/openvpn-user-linux-amd64.tar.gz -O - | tar xz -C /usr/local/bin && \ + wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.4/openvpn-user-linux-${TARGETARCH}.tar.gz -O - | tar xz -C /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* +RUN if [ -f "/usr/local/bin/openvpn-user-${TARGETARCH}" ]; then ln -s /usr/local/bin/openvpn-user-${TARGETARCH} /usr/local/bin/openvpn-user; fi \ No newline at end of file diff --git a/Dockerfile.openvpn b/Dockerfile.openvpn index ce80f40..12ddf94 100644 --- a/Dockerfile.openvpn +++ b/Dockerfile.openvpn @@ -1,7 +1,9 @@ FROM alpine:3.16 +ARG TARGETARCH RUN apk add --update bash openvpn easy-rsa iptables && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ - wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.4/openvpn-user-linux-amd64.tar.gz -O - | tar xz -C /usr/local/bin && \ + wget https://github.com/pashcovich/openvpn-user/releases/download/v1.0.4/openvpn-user-linux-${TARGETARCH}.tar.gz -O - | tar xz -C /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* +RUN if [ -f "/usr/local/bin/openvpn-user-${TARGETARCH}" ]; then ln -s /usr/local/bin/openvpn-user-${TARGETARCH} /usr/local/bin/openvpn-user; fi COPY setup/ /etc/openvpn/setup -RUN chmod +x /etc/openvpn/setup/configure.sh +RUN chmod +x /etc/openvpn/setup/configure.sh \ No newline at end of file diff --git a/main.go b/main.go index 97f9fa1..fb7e44e 100644 --- a/main.go +++ b/main.go @@ -94,9 +94,6 @@ var logFormats = map[string]log.Formatter{ "json": &log.JSONFormatter{}, } -var ( -) - var ( ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "ovpn_server_cert_expire", From 8a35f70364593acfbba91e8ee400fac17245ea71 Mon Sep 17 00:00:00 2001 From: Sprait Date: Fri, 8 Sep 2023 17:45:34 +0300 Subject: [PATCH 05/20] add variable for prometheus datasource to dashboard (#239) --- dashboard/ovpn-admin.json | 51 +++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/dashboard/ovpn-admin.json b/dashboard/ovpn-admin.json index bd01004..f7f83f7 100644 --- a/dashboard/ovpn-admin.json +++ b/dashboard/ovpn-admin.json @@ -31,7 +31,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -90,7 +90,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -149,7 +149,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -206,7 +206,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -263,7 +263,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -305,7 +305,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.2", + "pluginVersion": "8.5.13", "targets": [ { "expr": "ovpn_clients_expired", @@ -320,7 +320,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -381,7 +381,7 @@ "dashes": false, "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -469,7 +469,7 @@ "dashes": false, "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -557,7 +557,7 @@ "dashes": false, "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -647,7 +647,7 @@ "dashes": false, "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -733,7 +733,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "description": "value show last connection check time", "fieldConfig": { @@ -794,7 +794,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "description": "value shows when connection was started", "fieldConfig": { @@ -855,7 +855,7 @@ { "datasource": { "type": "prometheus", - "uid": "P0D6E4079E36703EB" + "uid": "$ds_prometheus" }, "fieldConfig": { "defaults": { @@ -928,7 +928,26 @@ "style": "dark", "tags": [], "templating": { - "list": [] + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "multi": false, + "label": "Prometheus", + "name": "ds_prometheus", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] }, "time": { "from": "now-15m", @@ -952,4 +971,4 @@ "uid": "Z7qmFI0Gk", "version": 1, "weekStart": "" -} +} \ No newline at end of file From 35f76ec3b69ce894d08c5bb4a45cc242dff94c30 Mon Sep 17 00:00:00 2001 From: Sprait Date: Mon, 11 Sep 2023 09:18:48 +0300 Subject: [PATCH 06/20] Update actions build binary (#240) * disable-386-build * update versison go-release-action --- .github/workflows/publish-latest.yaml | 4 ++-- .github/workflows/publish-tag.yaml | 4 ++-- .github/workflows/release.yaml | 2 +- .github/workflows/release_arm.yaml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-latest.yaml b/.github/workflows/publish-latest.yaml index 33cd3cc..ad1f8e4 100644 --- a/.github/workflows/publish-latest.yaml +++ b/.github/workflows/publish-latest.yaml @@ -23,13 +23,13 @@ jobs: uses: docker/build-push-action@v4 with: tags: flant/ovpn-admin:openvpn-latest - platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + platforms: linux/amd64,linux/arm64,linux/arm file: Dockerfile.openvpn push: true - name: Push ovpn-admin image to Docker Hub uses: docker/build-push-action@v4 with: tags: flant/ovpn-admin:latest - platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + platforms: linux/amd64,linux/arm64,linux/arm file: Dockerfile push: true \ No newline at end of file diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index 222b30f..06bdaef 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -27,13 +27,13 @@ jobs: uses: docker/build-push-action@v4 with: tags: flant/ovpn-admin:openvpn-${{ steps.get_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + platforms: linux/amd64,linux/arm64,linux/arm file: Dockerfile.openvpn push: true - name: Push ovpn-admin image to Docker Hub uses: docker/build-push-action@v4 with: tags: flant/ovpn-admin:${{ steps.get_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm64,linux/arm,linux/386 + platforms: linux/amd64,linux/arm64,linux/arm file: Dockerfile push: true \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d038490..482ba80 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,7 +17,7 @@ jobs: - name: checkout code uses: actions/checkout@v2 - name: build binaries - uses: wangyoucao577/go-release-action@v1.28 + uses: wangyoucao577/go-release-action@v1.40 with: github_token: ${{ secrets.GITHUB_TOKEN }} goversion: 1.17 diff --git a/.github/workflows/release_arm.yaml b/.github/workflows/release_arm.yaml index 3d52c12..d322571 100644 --- a/.github/workflows/release_arm.yaml +++ b/.github/workflows/release_arm.yaml @@ -17,7 +17,7 @@ jobs: - name: checkout code uses: actions/checkout@v2 - name: build binaries - uses: wangyoucao577/go-release-action@v1.28 + uses: wangyoucao577/go-release-action@v1.40 with: github_token: ${{ secrets.GITHUB_TOKEN }} goversion: 1.17 From c83c581e21ca3735764e4f2a6dff926a53605589 Mon Sep 17 00:00:00 2001 From: Sprait Date: Tue, 12 Sep 2023 11:05:28 +0300 Subject: [PATCH 07/20] fix revoke user (#243) * fix reuse argument multiple times * replace whitespace with tab --- main.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index fb7e44e..faf75ec 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,7 @@ const ( var ( listenHost = kingpin.Flag("listen.host", "host for ovpn-admin").Default("0.0.0.0").Envar("OVPN_LISTEN_HOST").String() listenPort = kingpin.Flag("listen.port", "port for ovpn-admin").Default("8080").Envar("OVPN_LISTEN_PORT").String() - listenBaseUrl = kingpin.Flag("listen.base-url", "base url for ovpn-admin").Default("/").Envar("OVPN_LISTEN_BASE_URL").String() + listenBaseUrl = kingpin.Flag("listen.base-url", "base url for ovpn-admin").Default("/").Envar("OVPN_LISTEN_BASE_URL").String() serverRole = kingpin.Flag("role", "server role, master or slave").Default("master").Envar("OVPN_ROLE").HintOptions("master", "slave").String() masterHost = kingpin.Flag("master.host", "URL for the master server").Default("http://127.0.0.1").Envar("OVPN_MASTER_HOST").String() masterBasicAuthUser = kingpin.Flag("master.basic-auth.user", "user for master server's Basic Auth").Default("").Envar("OVPN_MASTER_USER").String() @@ -64,7 +64,7 @@ var ( metricsPath = kingpin.Flag("metrics.path", "URL path for exposing collected metrics").Default("/metrics").Envar("OVPN_METRICS_PATH").String() easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa").Envar("EASYRSA_PATH").String() indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file").Default("").Envar("OVPN_INDEX_PATH").String() - easyrsaBinPath = kingpin.Flag("easyrsa.bin-path", "path to easyrsa script").Default("easyrsa").Envar("EASYRSA_BIN_PATH").String() + easyrsaBinPath = kingpin.Flag("easyrsa.bin-path", "path to easyrsa script").Default("easyrsa").Envar("EASYRSA_BIN_PATH").String() ccdEnabled = kingpin.Flag("ccd", "enable client-config-dir").Default("false").Envar("OVPN_CCD").Bool() ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").Envar("OVPN_CCD_PATH").String() clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").Envar("OVPN_TEMPLATES_CC_PATH").String() @@ -854,7 +854,7 @@ func (oAdmin *OvpnAdmin) getCcd(username string) Ccd { } func checkStaticAddressIsFree(staticAddress string, username string) bool { - o := runBash(fmt.Sprintf("grep -rl ' %s ' %s | grep -vx %s/%s | wc -l", staticAddress, *ccdDir, *ccdDir, username)) + o := runBash(fmt.Sprintf("grep -rl ' %[1]s ' %[2]s | grep -vx %[2]s/%[3]s | wc -l", staticAddress, *ccdDir, username)) if strings.TrimSpace(o) == "0" { return true @@ -1004,7 +1004,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) { func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (error, string) { if checkUserExist(username) { - o := runBash(fmt.Sprintf("openvpn-user check --db.path %s --user %s | grep %s | wc -l", *authDatabase, username, username)) + o := runBash(fmt.Sprintf("openvpn-user check --db.path %[1]s --user %[2]s | grep %[2]s | wc -l", *authDatabase, username)) log.Debug(o) if err := validatePassword(password); err != nil { @@ -1048,7 +1048,7 @@ func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) { log.Error(err) } } else { - o := runBash(fmt.Sprintf("cd %s && echo yes | easyrsa revoke %s 1>/dev/null && %s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath, username)) + o := runBash(fmt.Sprintf("cd %[1]s && echo yes | %[2]s revoke %[3]s 1>/dev/null && %[2]s gen-crl 1>/dev/null", *easyrsaDirPath, *easyrsaBinPath, username)) log.Debugln(o) } From d566bba73e74a289eb99ffbfce4ceeedfba4a96c Mon Sep 17 00:00:00 2001 From: Sprait Date: Thu, 5 Oct 2023 19:25:28 +0000 Subject: [PATCH 08/20] fix compose --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index d724624..8aa480d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -26,7 +26,7 @@ services: environment: OVPN_NETWORK: ${OVPN_NETWORK} OVPN_CCD: ${OVPN_CCD} - OVPN_CCD_PATH: ${OVPN_CCD_PATH + OVPN_CCD_PATH: ${OVPN_CCD_PATH} EASYRSA_PATH: ${EASYRSA_PATH} OVPN_SERVER: ${OVPN_SERVER} OVPN_INDEX_PATH: ${OVPN_INDEX_PATH} From efc44d1e5fff9de130b3c7ca8fc1924927adb8e7 Mon Sep 17 00:00:00 2001 From: Sprait Date: Fri, 6 Oct 2023 18:42:55 +0000 Subject: [PATCH 09/20] upd compose --- docker-compose.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 8aa480d..1717fd1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,7 +9,7 @@ services: environment: OVPN_SERVER_NET: ${OVPN_SERVER_NET} OVPN_SERVER_MASK: ${OVPN_SERVER_MASK} - OVPN_PASSWD_AUTH: ${OVPN_PASSWD_AUTH} + OVPN_AUTH: ${OVPN_AUTH} cap_add: - NET_ADMIN ports: @@ -31,7 +31,6 @@ services: OVPN_SERVER: ${OVPN_SERVER} OVPN_INDEX_PATH: ${OVPN_INDEX_PATH} OVPN_AUTH: ${OVPN_AUTH} - OVPN_AUTH_TFA: ${OVPN_AUTH_TFA} OVPN_AUTH_DB_PATH: ${OVPN_AUTH_DB_PATH} LOG_LEVEL: ${LOG_LEVEL} network_mode: service:openvpn From c168f368623a952506edc87bc481575996a268c6 Mon Sep 17 00:00:00 2001 From: Sprait Date: Fri, 6 Oct 2023 18:47:28 +0000 Subject: [PATCH 10/20] fix passw auth; refactor type auth --- backend/errors.go | 4 +-- backend/flags.go | 3 +- backend/handlers.go | 4 +-- backend/methods.go | 66 +++++++++++++++++++++++++++----------- backend/models.go | 3 +- backend/utils.go | 18 +++++++++++ frontend/src/main.js | 15 +++++---- frontend/static/index.html | 19 ++++++----- main.go | 33 +++++++------------ setup/auth.sh | 2 +- setup/configure.sh | 2 +- 11 files changed, 106 insertions(+), 63 deletions(-) diff --git a/backend/errors.go b/backend/errors.go index 1118de6..5979e81 100644 --- a/backend/errors.go +++ b/backend/errors.go @@ -12,7 +12,7 @@ var ( userIsNotActiveError = errors.New("user is not active") passwordMismatchedError = errors.New("password mismatched") tokenMismatchedError = errors.New("token mismatched") - checkAppError = errors.New("failed to check 2FA app") - registerAppError = errors.New("failed to register 2FA app") + checkAppError = errors.New("failed to check 2FA TOTP app") + registerAppError = errors.New("failed to register 2FA TOTP app") authBackendDisabled = errors.New("auth backend not enabled yet") ) diff --git a/backend/flags.go b/backend/flags.go index 7edbd48..03d2287 100644 --- a/backend/flags.go +++ b/backend/flags.go @@ -36,8 +36,7 @@ var ( clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").Envar("OVPN_TEMPLATES_CC_PATH").String() ccdTemplatePath = kingpin.Flag("templates.ccd-path", "path to custom ccd.tpl").Default("").Envar("OVPN_TEMPLATES_CCD_PATH").String() - AuthByPassword = kingpin.Flag("auth.password", "enable additional password authentication").Default("false").Envar("OVPN_AUTH").Bool() - AuthTFA = kingpin.Flag("auth.2fa", "auth type").Default("false").Envar("OVPN_AUTH_TFA").Bool() + AuthType = kingpin.Flag("auth.type", "auth type").Default("").Envar("OVPN_AUTH").HintOptions("TOTP", "PASSWORD", "").String() AuthDatabase = kingpin.Flag("auth.db", "database path for password authentication").Default("./easyrsa/pki/users.db").Envar("OVPN_AUTH_DB_PATH").String() LogLevel = kingpin.Flag("log.level", "set log level: trace, debug, info, warn, error (default info)").Default("info").Envar("LOG_LEVEL").String() diff --git a/backend/handlers.go b/backend/handlers.go index 9ed6cea..1aa0d9f 100644 --- a/backend/handlers.go +++ b/backend/handlers.go @@ -74,7 +74,7 @@ func (oAdmin *OvpnAdmin) UserResetTFAHandler(w http.ResponseWriter, r *http.Requ http.Error(w, err.Error(), http.StatusBadRequest) } else { w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "2FA reseted") + fmt.Fprintf(w, "TOTP reseted") } } @@ -150,7 +150,7 @@ func (oAdmin *OvpnAdmin) UserUnrevokeHandler(w http.ResponseWriter, r *http.Requ func (oAdmin *OvpnAdmin) UserChangePasswordHandler(w http.ResponseWriter, r *http.Request) { log.Info(r.RemoteAddr, " ", r.RequestURI) _ = r.ParseForm() - if *AuthByPassword { + if oAdmin.ExtraAuth { err, msg := oAdmin.userChangePassword(r.FormValue("username"), r.FormValue("password")) if err != nil { w.WriteHeader(http.StatusInternalServerError) diff --git a/backend/methods.go b/backend/methods.go index 9434465..5dfabb8 100644 --- a/backend/methods.go +++ b/backend/methods.go @@ -152,7 +152,7 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string { conf.Key = fRead(*EasyrsaDirPath + "/pki/private/" + username + ".key") } - conf.PasswdAuth = *AuthByPassword + conf.PasswdAuth = oAdmin.ExtraAuth t := oAdmin.getTemplate("client.conf.tpl", "client-config", *clientConfigTemplatePath) @@ -313,8 +313,12 @@ func (oAdmin *OvpnAdmin) usersList() []OpenvpnClient { connectedUniqUsers += 1 } - if oAdmin.isSecondFactorConfigured(ovpnClient.Identity) { - ovpnClient.SecondFactor = true + if oAdmin.ExtraAuth{ + if oAdmin.isSecondFactorConfigured(ovpnClient.Identity) { + ovpnClient.SecondFactor = "enabled" + } else { + ovpnClient.SecondFactor = "disabled" + } } users = append(users, ovpnClient) @@ -354,7 +358,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (string, error) { return err.Error(), err } - if *AuthByPassword { + if oAdmin.ExtraAuth { if err := validatePassword(password); err != nil { log.Debugf("userCreate: authByPassword(): %s", err.Error()) return err.Error(), err @@ -367,7 +371,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (string, error) { log.Error(err) return err.Error(), err } - if *AuthByPassword { + if oAdmin.ExtraAuth { err = oAdmin.KubeClient.updatePasswordSecret(username, []byte(password)) if err != nil { return err.Error(), err @@ -376,7 +380,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (string, error) { } else { o := runBash(fmt.Sprintf("cd %s && easyrsa build-client-full %s nopass 1>/dev/null", *EasyrsaDirPath, username)) log.Debug(o) - if *AuthByPassword { + if oAdmin.ExtraAuth { _, err := oAdmin.OUser.CreateUser(username, password) if err != nil { return err.Error(), err @@ -435,14 +439,21 @@ func (oAdmin *OvpnAdmin) isSecondFactorConfigured(username string) bool { } return sfe case "filesystem": - sfe, err := oAdmin.OUser.IsSecondFactorEnabled(username) - if err != nil { - return false + switch *AuthType { + case "TOTP": + sfe, err := oAdmin.OUser.IsSecondFactorEnabled(username) + if err != nil { + return false + } + return sfe + case "PASSWORD": + return true + //TODO: check if password is exist in db } - return sfe default: return false } + return false } func (oAdmin *OvpnAdmin) getUserSecret(username string) (string, error) { @@ -538,11 +549,11 @@ func (oAdmin *OvpnAdmin) registerUserAuthApp(username, totp string) error { for i, u := range oAdmin.clients { if u.Identity == username { - oAdmin.clients[i].SecondFactor = true + oAdmin.clients[i].SecondFactor = "enabled" } } - log.Infof("2FA configured for user %s", username) + log.Infof("TOTP configured for user %s", username) return nil } return fmt.Errorf("user \"%s\" not found", username) @@ -567,7 +578,7 @@ func (oAdmin *OvpnAdmin) resetUserAuthApp(username string) error { for i, u := range oAdmin.clients { if u.Identity == username { - oAdmin.clients[i].SecondFactor = false + oAdmin.clients[i].SecondFactor = "disabled" } } return nil @@ -587,7 +598,12 @@ func (oAdmin *OvpnAdmin) checkAuth(username, token string) error { return authErr } } else { - auth, authErr = oAdmin.OUser.AuthUser(username, "", token) + switch *AuthType { + case "TOTP": + auth, authErr = oAdmin.OUser.AuthUser(username, "", token) + case "PASSWORD": + auth, authErr = oAdmin.OUser.AuthUser(username, token, "") + } if authErr != nil { return authErr } @@ -625,7 +641,7 @@ func (oAdmin *OvpnAdmin) userRevoke(username string) (error, string) { log.Debugln(o) } - if *AuthByPassword { + if oAdmin.ExtraAuth { if oAdmin.OUser.CheckUserExistent(username) { revokeMsg, revokeErr := oAdmin.OUser.RevokedUser(username) log.Debug(revokeMsg) @@ -693,7 +709,7 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) (error, string) { _ = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl 1>/dev/null", *EasyrsaDirPath)) - if *AuthByPassword { + if oAdmin.ExtraAuth { if oAdmin.OUser.CheckUserExistent(username) { restoreMsg, restoreErr := oAdmin.OUser.RestoreUser(username) log.Debug(restoreMsg) @@ -750,7 +766,7 @@ func (oAdmin *OvpnAdmin) userRotate(username, newPassword string) (error, string log.Error(err) } - if *AuthByPassword { + if oAdmin.ExtraAuth { if oAdmin.OUser.CheckUserExistent(username) { deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true) log.Debug(deleteMsg) @@ -819,7 +835,7 @@ func (oAdmin *OvpnAdmin) userDelete(username string) (error, string) { break } } - if *AuthByPassword { + if oAdmin.ExtraAuth { if oAdmin.OUser.CheckUserExistent(username) { deleteMsg, deleteErr := oAdmin.OUser.DeleteUser(username, true) log.Debug(deleteMsg) @@ -1095,3 +1111,17 @@ func (oAdmin *OvpnAdmin) SyncWithMaster() { oAdmin.SyncDataFromMaster() } } + +func (oAdmin *OvpnAdmin) IsTotpAuth() bool { + if IsModuleEnabled("totpAuth", oAdmin.Modules) { + return true + } + return false +} + +func (oAdmin *OvpnAdmin) IsPasswdAuth() bool { + if IsModuleEnabled("passwdAuth", oAdmin.Modules) { + return true + } + return false +} \ No newline at end of file diff --git a/backend/models.go b/backend/models.go index 049b850..0e9d486 100644 --- a/backend/models.go +++ b/backend/models.go @@ -24,6 +24,7 @@ type OvpnAdmin struct { Modules []string mgmtStatusTimeFormat string CreateUserMutex *sync.Mutex + ExtraAuth bool } type OpenvpnServer struct { @@ -48,7 +49,7 @@ type OpenvpnClient struct { RevocationDate string `json:"RevocationDate"` ConnectionStatus string `json:"ConnectionStatus"` Connections int `json:"Connections"` - SecondFactor bool `json:"SecondFactor"` + SecondFactor string `json:"SecondFactor,omitempty"` } type ccdRoute struct { diff --git a/backend/utils.go b/backend/utils.go index be36465..0462124 100644 --- a/backend/utils.go +++ b/backend/utils.go @@ -24,6 +24,7 @@ import ( "strings" "time" "unicode/utf8" + "database/sql" ) var ( @@ -555,3 +556,20 @@ func randStr(strSize int, randType string) string { } return string(bytes) } + +func OpenDB(path string) *sql.DB { + db, err := sql.Open("sqlite3", path) + if err != nil { + log.Fatal(err) + } + return db +} + +func IsModuleEnabled(desiredModule string, listModules []string) bool { + for _, module := range listModules { + if module == desiredModule { + return true + } + } + return false +} \ No newline at end of file diff --git a/frontend/src/main.js b/frontend/src/main.js index 2c11f7a..6bb1497 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -160,6 +160,7 @@ new Vue({ label: 'Download config', class: 'btn-info', showWhenStatus: 'Active', + Require2FA: "true", showForServerRole: ['master', 'slave'], showForModule: ["core"], }, @@ -353,7 +354,7 @@ new Vue({ getUserTFAData: function(data) { let _this = this; - if (!_this.secondfactor) { + if (_this.secondfactor == 'disabled' ) { axios.request(axios_cfg('api/user/2fa/secret', data, 'form')) .then(function (response) { _this.u.secret = response.data; @@ -374,15 +375,15 @@ new Vue({ _this.u.modalActionStatus = 200; _this.u.modalRegister2faVisible = false; _this.getUserData(); - _this.secondfactor = true; + _this.secondfactor = "enabled"; _this.u.token = ""; _this.u.secret = ""; - _this.$notify({title: '2FA application registered for user ' + username, type: 'success'}); + _this.$notify({title: 'TOTP application registered for user ' + username, type: 'success'}); }) .catch(function(error) { _this.u.modalActionStatus = error.response.status; _this.u.modalActionMessage = error.response.data.message; - _this.$notify({title: 'Register 2FA application for user ' + username + ' failed!', type: 'error'}); + _this.$notify({title: 'Register TOTP application for user ' + username + ' failed!', type: 'error'}); }) }, @@ -396,15 +397,15 @@ new Vue({ axios.request(axios_cfg('api/user/2fa/reset', data, 'form')) .then(function(response) { _this.u.modalActionStatus = 200; - _this.secondfactor = false; + _this.secondfactor = "disabled"; _this.getUserTFAData(data); _this.getUserData(); - _this.$notify({title: '2FA application reset for user ' + username, type: 'success'}); + _this.$notify({title: 'TOTP application reset for user ' + username, type: 'success'}); }) .catch(function(error) { _this.u.modalActionStatus = error.response.status; _this.u.modalActionMessage = error.response.data.message; - _this.$notify({title: 'Reset 2FA application for user ' + username + ' failed!', type: 'error'}); + _this.$notify({title: 'Reset TOTP application for user ' + username + ' failed!', type: 'error'}); }) }, diff --git a/frontend/static/index.html b/frontend/static/index.html index 4e86bca..6f07a51 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -36,7 +36,10 @@ @click.left.stop="rowActionFn" v-for="action in actions" v-bind:class="action.class" - v-if="action.showWhenStatus == props.row.AccountStatus && action.showForServerRole.includes(serverRole) && action.showForModule.some(p=> modulesEnabled.includes(p))"> + v-if="action.showWhenStatus == props.row.AccountStatus && + ( props.row.SecondFactor != 'disabled' || !(action.Require2FA) ) && + action.showForServerRole.includes(serverRole) && + action.showForModule.some(p=> modulesEnabled.includes(p))"> {{ action.label }} @@ -51,7 +54,7 @@