mirror of
https://github.com/nezhahq/nezha.git
synced 2025-01-22 12:48:14 -05:00
Compare commits
10 Commits
59b5f4598d
...
f127ff8141
Author | SHA1 | Date | |
---|---|---|---|
|
f127ff8141 | ||
|
a5dbc5693d | ||
|
4754d283c9 | ||
|
d835aeb486 | ||
|
c952ed0e38 | ||
|
35d137d4ea | ||
|
c32dd4cd75 | ||
|
a9c2abe71e | ||
|
65d7e4cb98 | ||
|
c1fdd00cf0 |
@ -67,11 +67,11 @@ add your theme to [service/singleton/frontend-templates.yaml](service/singleton/
|
||||
<a href="https://github.com/iilemon" title="Sean"><img src="https://avatars.githubusercontent.com/u/33201711?v=4" width="50;" alt="Sean"/></a>
|
||||
<a href="https://github.com/fscarmen" title="fscarmen"><img src="https://avatars.githubusercontent.com/u/62703343?v=4" width="50;" alt="fscarmen"/></a>
|
||||
<a href="https://github.com/ch8o" title="no-name-now"><img src="https://avatars.githubusercontent.com/u/9103372?v=4" width="50;" alt="no-name-now"/></a>
|
||||
<a href="https://github.com/weblate" title="Weblate (bot)"><img src="https://avatars.githubusercontent.com/u/1607653?v=4" width="50;" alt="Weblate (bot)"/></a>
|
||||
<a href="https://github.com/HsukqiLee" title="HsukqiLee"><img src="https://avatars.githubusercontent.com/u/79034142?v=4" width="50;" alt="HsukqiLee"/></a>
|
||||
<a href="https://github.com/DarcJC" title="Darc Z."><img src="https://avatars.githubusercontent.com/u/53445798?v=4" width="50;" alt="Darc Z."/></a>
|
||||
<a href="https://github.com/Creling" title="Creling"><img src="https://avatars.githubusercontent.com/u/43109504?v=4" width="50;" alt="Creling"/></a>
|
||||
<a href="https://github.com/coreff" title="Core F"><img src="https://avatars.githubusercontent.com/u/38347122?v=4" width="50;" alt="Core F"/></a>
|
||||
<a href="https://github.com/weblate" title="Weblate (bot)"><img src="https://avatars.githubusercontent.com/u/1607653?v=4" width="50;" alt="Weblate (bot)"/></a>
|
||||
<a href="https://github.com/adminsama" title="adminsama"><img src="https://avatars.githubusercontent.com/u/60880076?v=4" width="50;" alt="adminsama"/></a>
|
||||
<a href="https://github.com/acgpiano" title="Acgpiano"><img src="https://avatars.githubusercontent.com/u/15900800?v=4" width="50;" alt="Acgpiano"/></a>
|
||||
<a href="https://github.com/eya46" title="eya46"><img src="https://avatars.githubusercontent.com/u/61458340?v=4" width="50;" alt="eya46"/></a>
|
||||
|
@ -79,7 +79,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
||||
|
||||
auth.GET("/profile", commonHandler(getProfile))
|
||||
auth.POST("/profile", commonHandler(updateProfile))
|
||||
auth.GET("/user", commonHandler(listUser))
|
||||
auth.GET("/user", adminHandler(listUser))
|
||||
auth.POST("/user", adminHandler(createUser))
|
||||
auth.POST("/batch-delete/user", adminHandler(batchDeleteUser))
|
||||
|
||||
@ -97,7 +97,7 @@ func routers(r *gin.Engine, frontendDist fs.FS) {
|
||||
auth.PATCH("/notification-group/:id", commonHandler(updateNotificationGroup))
|
||||
auth.POST("/batch-delete/notification-group", commonHandler(batchDeleteNotificationGroup))
|
||||
|
||||
auth.GET("/server", listHandler(listServer))
|
||||
auth.GET("/server", commonHandler(listServer))
|
||||
auth.PATCH("/server/:id", commonHandler(updateServer))
|
||||
auth.POST("/batch-delete/server", commonHandler(batchDeleteServer))
|
||||
auth.POST("/force-update/server", commonHandler(forceUpdateServer))
|
||||
@ -243,13 +243,13 @@ func listHandler[S ~[]E, E model.CommonInterface](handler handlerFunc[S]) func(*
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, filter(c, data))
|
||||
c.JSON(http.StatusOK, model.CommonResponse[S]{Success: true, Data: filter(c, data)})
|
||||
}
|
||||
}
|
||||
|
||||
func filter[S ~[]E, E model.CommonInterface](ctx *gin.Context, s S) S {
|
||||
return slices.DeleteFunc(s, func(e E) bool {
|
||||
return e.HasPermission(ctx)
|
||||
return !e.HasPermission(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -168,6 +168,10 @@ func manualTriggerCron(c *gin.Context) (any, error) {
|
||||
}
|
||||
singleton.CronLock.RUnlock()
|
||||
|
||||
if !cr.HasPermission(c) {
|
||||
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||
}
|
||||
|
||||
singleton.ManualTrigger(cr)
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ func batchDeleteNotificationGroup(c *gin.Context) (any, error) {
|
||||
}
|
||||
|
||||
var ng []model.NotificationGroup
|
||||
if err := singleton.DB.Where("id in (?)", ng).Find(&ng).Error; err != nil {
|
||||
if err := singleton.DB.Where("id in (?)", ngnr).Find(&ng).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,9 @@ func forceUpdateServer(c *gin.Context) (*model.ForceUpdateResponse, error) {
|
||||
server := singleton.ServerList[sid]
|
||||
singleton.ServerLock.RUnlock()
|
||||
if server != nil && server.TaskStream != nil {
|
||||
if !server.HasPermission(c) {
|
||||
return nil, singleton.Localizer.ErrorT("permission denied")
|
||||
}
|
||||
if err := server.TaskStream.Send(&pb.Task{
|
||||
Type: model.TaskTypeUpgrade,
|
||||
}); err != nil {
|
||||
|
@ -126,6 +126,7 @@ func createUser(c *gin.Context) (uint64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
singleton.OnUserUpdate(&u)
|
||||
return u.ID, nil
|
||||
}
|
||||
|
||||
@ -150,5 +151,6 @@ func batchDeleteUser(c *gin.Context) (any, error) {
|
||||
return nil, singleton.Localizer.ErrorT("can't delete yourself")
|
||||
}
|
||||
|
||||
singleton.OnUserDelete(ids)
|
||||
return nil, singleton.DB.Where("id IN (?)", ids).Delete(&model.User{}).Error
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ type Common struct {
|
||||
// Do not use soft deletion
|
||||
// DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
|
||||
|
||||
UserID uint64 `json:"user_id,omitempty"`
|
||||
UserID uint64 `json:"-"`
|
||||
}
|
||||
|
||||
func (c *Common) GetID() uint64 {
|
||||
|
@ -1,5 +1,10 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/nezhahq/nezha/pkg/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
RoleAdmin uint8 = iota
|
||||
RoleMember
|
||||
@ -7,9 +12,20 @@ const (
|
||||
|
||||
type User struct {
|
||||
Common
|
||||
Username string `json:"username,omitempty" gorm:"uniqueIndex"`
|
||||
Password string `json:"password,omitempty" gorm:"type:char(72)"`
|
||||
Role uint8 `json:"role,omitempty"`
|
||||
Username string `json:"username,omitempty" gorm:"uniqueIndex"`
|
||||
Password string `json:"password,omitempty" gorm:"type:char(72)"`
|
||||
Role uint8 `json:"role,omitempty"`
|
||||
AgentSecret string `json:"agent_secret,omitempty" gorm:"type:char(32)"`
|
||||
}
|
||||
|
||||
func (u *User) BeforeSave(tx *gorm.DB) error {
|
||||
key, err := utils.GenerateRandomString(32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.AgentSecret = key
|
||||
return nil
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
|
@ -1,6 +0,0 @@
|
||||
package model
|
||||
|
||||
type UserGroup struct {
|
||||
Common
|
||||
Name string `json:"name"`
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package model
|
||||
|
||||
type UserGroupUser struct {
|
||||
Common
|
||||
UserGroupId uint64 `json:"user_group_id"`
|
||||
UserId uint64 `json:"user_id"`
|
||||
}
|
@ -16,6 +16,7 @@ var Languages = map[string]string{
|
||||
"zh_TW": "繁體中文",
|
||||
"en_US": "English",
|
||||
"es_ES": "Español",
|
||||
"de_DE": "Deutsch",
|
||||
}
|
||||
|
||||
type Localizer struct {
|
||||
|
BIN
pkg/i18n/translations/de_DE/LC_MESSAGES/nezha.mo
Normal file
BIN
pkg/i18n/translations/de_DE/LC_MESSAGES/nezha.mo
Normal file
Binary file not shown.
228
pkg/i18n/translations/de_DE/LC_MESSAGES/nezha.po
Normal file
228
pkg/i18n/translations/de_DE/LC_MESSAGES/nezha.po
Normal file
@ -0,0 +1,228 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-23 23:56+0800\n"
|
||||
"PO-Revision-Date: 2024-12-17 04:52+0000\n"
|
||||
"Last-Translator: UUBulb <uub@kuzu.uk>\n"
|
||||
"Language-Team: German <https://hosted.weblate.org/projects/nezha/"
|
||||
"nezha-dashboard/de/>\n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.9\n"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:100
|
||||
#, c-format
|
||||
msgid "alert id %d does not exist"
|
||||
msgstr "benachrichtigungs ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:155
|
||||
msgid "duration need to be at least 3"
|
||||
msgstr "dauer muss mindestens 3 sein"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:159
|
||||
msgid "cycle_interval need to be at least 1"
|
||||
msgstr "cycle_interval muss mindestens 1 sein"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:162
|
||||
msgid "cycle_start is not set"
|
||||
msgstr "cycle_start ist nicht eingestellt"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:165
|
||||
msgid "cycle_start is a future value"
|
||||
msgstr "cycle_start ist ein zukünftiger wert"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:170
|
||||
msgid "need to configure at least a single rule"
|
||||
msgstr "mindestens eine Regel muss konfiguriert sein"
|
||||
|
||||
#: cmd/dashboard/controller/controller.go:195
|
||||
msgid "database error"
|
||||
msgstr "datenbankfehler"
|
||||
|
||||
#: cmd/dashboard/controller/cron.go:63 cmd/dashboard/controller/cron.go:122
|
||||
msgid "scheduled tasks cannot be triggered by alarms"
|
||||
msgstr "geplante aufgaben können nicht durch Alarme ausgelöst werden"
|
||||
|
||||
#: cmd/dashboard/controller/cron.go:161
|
||||
#, c-format
|
||||
msgid "task id %d does not exist"
|
||||
msgstr "task ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:56 cmd/dashboard/controller/ddns.go:120
|
||||
msgid "the retry count must be an integer between 1 and 10"
|
||||
msgstr "der retry_count muss eine Zahl zwischen 1 und 10 sein"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:79 cmd/dashboard/controller/ddns.go:148
|
||||
msgid "error parsing %s: %v"
|
||||
msgstr "fehler beim parsen von %s: %v"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:125 cmd/dashboard/controller/nat.go:95
|
||||
#, c-format
|
||||
msgid "profile id %d does not exist"
|
||||
msgstr "profil ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/fm.go:45 cmd/dashboard/controller/terminal.go:43
|
||||
msgid "server not found or not connected"
|
||||
msgstr "server nicht gefunden oder nicht verbunden"
|
||||
|
||||
#: cmd/dashboard/controller/notification.go:67
|
||||
#: cmd/dashboard/controller/notification.go:125
|
||||
msgid "a test message"
|
||||
msgstr "testnachricht"
|
||||
|
||||
#: cmd/dashboard/controller/notification.go:106
|
||||
#, c-format
|
||||
msgid "notification id %d does not exist"
|
||||
msgstr "benachrichtigung ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/notification_group.go:80
|
||||
#: cmd/dashboard/controller/notification_group.go:142
|
||||
msgid "have invalid notification id"
|
||||
msgstr "haben ungültige Benachrichtigungs ID"
|
||||
|
||||
#: cmd/dashboard/controller/notification_group.go:131
|
||||
#: cmd/dashboard/controller/server_group.go:130
|
||||
#, c-format
|
||||
msgid "group id %d does not exist"
|
||||
msgstr "gruppen ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/server.go:60
|
||||
#, c-format
|
||||
msgid "server id %d does not exist"
|
||||
msgstr "server ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/server_group.go:78
|
||||
#: cmd/dashboard/controller/server_group.go:139
|
||||
msgid "have invalid server id"
|
||||
msgstr "haben ungültige Server ID"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:79
|
||||
#: cmd/dashboard/controller/service.go:155
|
||||
msgid "server not found"
|
||||
msgstr "server nicht gefunden"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:86 cmd/dashboard/controller/user.go:23
|
||||
msgid "unauthorized"
|
||||
msgstr "nicht autorisiert"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:247
|
||||
#, c-format
|
||||
msgid "service id %d does not exist"
|
||||
msgstr "service ID %d existiert nicht"
|
||||
|
||||
#: cmd/dashboard/controller/user.go:66
|
||||
msgid "password length must be greater than 6"
|
||||
msgstr "passwort muss länger als 6 Zeichen sein"
|
||||
|
||||
#: cmd/dashboard/controller/user.go:69
|
||||
msgid "username can't be empty"
|
||||
msgstr "benutzername darf nicht leer sein"
|
||||
|
||||
#: service/rpc/io_stream.go:122
|
||||
msgid "timeout: no connection established"
|
||||
msgstr "timeout: Keine Verbindung hergestellt"
|
||||
|
||||
#: service/rpc/io_stream.go:125
|
||||
msgid "timeout: user connection not established"
|
||||
msgstr "timeout: Benutzerverbindung nicht etabliert"
|
||||
|
||||
#: service/rpc/io_stream.go:128
|
||||
msgid "timeout: agent connection not established"
|
||||
msgstr "timeout: Agent-Verbindung nicht etabliert"
|
||||
|
||||
#: service/rpc/nezha.go:58
|
||||
msgid "Scheduled Task Executed Successfully"
|
||||
msgstr "geplante Aufgabe erfolgreich ausgeführt"
|
||||
|
||||
#: service/rpc/nezha.go:62
|
||||
msgid "Scheduled Task Executed Failed"
|
||||
msgstr "geplante Aufgabe fehlgeschlagen"
|
||||
|
||||
#: service/rpc/nezha.go:217
|
||||
msgid "IP Changed"
|
||||
msgstr "IP geändert"
|
||||
|
||||
#: service/singleton/alertsentinel.go:159
|
||||
msgid "Incident"
|
||||
msgstr "Vorfall"
|
||||
|
||||
#: service/singleton/alertsentinel.go:169
|
||||
msgid "Resolved"
|
||||
msgstr "Gelöst"
|
||||
|
||||
#: service/singleton/crontask.go:53
|
||||
msgid "Tasks failed to register: ["
|
||||
msgstr "Aufgaben konnten nicht registriert werden: ["
|
||||
|
||||
#: service/singleton/crontask.go:60
|
||||
msgid ""
|
||||
"] These tasks will not execute properly. Fix them in the admin dashboard."
|
||||
msgstr ""
|
||||
"] Diese Aufgaben werden nicht korrekt ausgeführt. Reparieren Sie diese im "
|
||||
"Admin-Dashboard."
|
||||
|
||||
#: service/singleton/crontask.go:146 service/singleton/crontask.go:171
|
||||
#, c-format
|
||||
msgid "[Task failed] %s: server %s is offline and cannot execute the task"
|
||||
msgstr ""
|
||||
"[Aufgabe fehlgeschlagen] %s: Server %s ist offline und kann die Aufgabe "
|
||||
"nicht ausführen"
|
||||
|
||||
#: service/singleton/servicesentinel.go:439
|
||||
#, c-format
|
||||
msgid "[Latency] %s %2f > %2f, Reporter: %s"
|
||||
msgstr "[Latency] %s %2f > %2f, Reporter: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:446
|
||||
#, c-format
|
||||
msgid "[Latency] %s %2f < %2f, Reporter: %s"
|
||||
msgstr "[Latency] %s %2f < %2f, Reporter: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:472
|
||||
#, c-format
|
||||
msgid "[%s] %s Reporter: %s, Error: %s"
|
||||
msgstr "[%s] %s Reporter: %s, Fehler: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:515
|
||||
#, c-format
|
||||
msgid "[TLS] Fetch cert info failed, Reporter: %s, Error: %s"
|
||||
msgstr "[TLS] Fetch cert info gescheitert, Reporter: %s, Fehler: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:555
|
||||
#, c-format
|
||||
msgid "The TLS certificate will expire within seven days. Expiration time: %s"
|
||||
msgstr "Das TLS-Zertifikat läuft innerhalb von sieben Tagen ab. Ablaufzeit: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:568
|
||||
#, c-format
|
||||
msgid ""
|
||||
"TLS certificate changed, old: issuer %s, expires at %s; new: issuer %s, "
|
||||
"expires at %s"
|
||||
msgstr ""
|
||||
"TLS-Zertifikat geändert, alt: Emittent %s, läuft ab bei %s; neu: Emittent "
|
||||
"%s, läuft ab bei %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:604
|
||||
msgid "No Data"
|
||||
msgstr "Keine Daten"
|
||||
|
||||
#: service/singleton/servicesentinel.go:606
|
||||
msgid "Good"
|
||||
msgstr "Gut"
|
||||
|
||||
#: service/singleton/servicesentinel.go:608
|
||||
msgid "Low Availability"
|
||||
msgstr "Niedere Verfügbarkeit"
|
||||
|
||||
#: service/singleton/servicesentinel.go:610
|
||||
msgid "Down"
|
||||
msgstr "Unten"
|
BIN
pkg/i18n/translations/es_ES/LC_MESSAGES/nezha.mo
Normal file
BIN
pkg/i18n/translations/es_ES/LC_MESSAGES/nezha.mo
Normal file
Binary file not shown.
232
pkg/i18n/translations/es_ES/LC_MESSAGES/nezha.po
Normal file
232
pkg/i18n/translations/es_ES/LC_MESSAGES/nezha.po
Normal file
@ -0,0 +1,232 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-23 23:56+0800\n"
|
||||
"PO-Revision-Date: 2024-12-17 04:52+0000\n"
|
||||
"Last-Translator: UUBulb <uub@kuzu.uk>\n"
|
||||
"Language-Team: Spanish <https://hosted.weblate.org/projects/nezha/"
|
||||
"nezha-dashboard/es/>\n"
|
||||
"Language: es_ES\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.9\n"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:100
|
||||
#, c-format
|
||||
msgid "alert id %d does not exist"
|
||||
msgstr "el ID de alerta %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:155
|
||||
msgid "duration need to be at least 3"
|
||||
msgstr "la duración debe ser al menos de 3"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:159
|
||||
msgid "cycle_interval need to be at least 1"
|
||||
msgstr "cycle_interval debe ser al menos 1"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:162
|
||||
msgid "cycle_start is not set"
|
||||
msgstr "no se ha configurado el cycle_start"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:165
|
||||
msgid "cycle_start is a future value"
|
||||
msgstr "cycle_start es un valor futuro"
|
||||
|
||||
#: cmd/dashboard/controller/alertrule.go:170
|
||||
msgid "need to configure at least a single rule"
|
||||
msgstr "es necesario configurar al menos una regla"
|
||||
|
||||
#: cmd/dashboard/controller/controller.go:195
|
||||
msgid "database error"
|
||||
msgstr "error de base de datos"
|
||||
|
||||
#: cmd/dashboard/controller/cron.go:63 cmd/dashboard/controller/cron.go:122
|
||||
msgid "scheduled tasks cannot be triggered by alarms"
|
||||
msgstr "las tareas programadas no pueden ser activadas por alarmas"
|
||||
|
||||
#: cmd/dashboard/controller/cron.go:161
|
||||
#, c-format
|
||||
msgid "task id %d does not exist"
|
||||
msgstr "el ID de la tarea %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:56 cmd/dashboard/controller/ddns.go:120
|
||||
msgid "the retry count must be an integer between 1 and 10"
|
||||
msgstr "el número de reintentos debe ser un número entero entre 1 y 10"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:79 cmd/dashboard/controller/ddns.go:148
|
||||
msgid "error parsing %s: %v"
|
||||
msgstr "error al analizar %s: %v"
|
||||
|
||||
#: cmd/dashboard/controller/ddns.go:125 cmd/dashboard/controller/nat.go:95
|
||||
#, c-format
|
||||
msgid "profile id %d does not exist"
|
||||
msgstr "el ID de perfil %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/fm.go:45 cmd/dashboard/controller/terminal.go:43
|
||||
msgid "server not found or not connected"
|
||||
msgstr "servidor no encontrado o no conectado"
|
||||
|
||||
#: cmd/dashboard/controller/notification.go:67
|
||||
#: cmd/dashboard/controller/notification.go:125
|
||||
msgid "a test message"
|
||||
msgstr "un mensaje de prueba"
|
||||
|
||||
#: cmd/dashboard/controller/notification.go:106
|
||||
#, c-format
|
||||
msgid "notification id %d does not exist"
|
||||
msgstr "el ID de notificación %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/notification_group.go:80
|
||||
#: cmd/dashboard/controller/notification_group.go:142
|
||||
msgid "have invalid notification id"
|
||||
msgstr "hay un ID de notificación no válido"
|
||||
|
||||
#: cmd/dashboard/controller/notification_group.go:131
|
||||
#: cmd/dashboard/controller/server_group.go:130
|
||||
#, c-format
|
||||
msgid "group id %d does not exist"
|
||||
msgstr "el ID de grupo %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/server.go:60
|
||||
#, c-format
|
||||
msgid "server id %d does not exist"
|
||||
msgstr "el ID de servidor %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/server_group.go:78
|
||||
#: cmd/dashboard/controller/server_group.go:139
|
||||
msgid "have invalid server id"
|
||||
msgstr "hay un ID de servidor no válido"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:79
|
||||
#: cmd/dashboard/controller/service.go:155
|
||||
msgid "server not found"
|
||||
msgstr "servidor no encontrado"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:86 cmd/dashboard/controller/user.go:23
|
||||
msgid "unauthorized"
|
||||
msgstr "no autorizado"
|
||||
|
||||
#: cmd/dashboard/controller/service.go:247
|
||||
#, c-format
|
||||
msgid "service id %d does not exist"
|
||||
msgstr "el ID de servicio %d no existe"
|
||||
|
||||
#: cmd/dashboard/controller/user.go:66
|
||||
msgid "password length must be greater than 6"
|
||||
msgstr "la longitud de la contraseña debe ser mayor a 6"
|
||||
|
||||
#: cmd/dashboard/controller/user.go:69
|
||||
msgid "username can't be empty"
|
||||
msgstr "el nombre de usuario no puede estar vacío"
|
||||
|
||||
#: service/rpc/io_stream.go:122
|
||||
msgid "timeout: no connection established"
|
||||
msgstr "tiempo de espera agotado: no se pudo establecer conexión"
|
||||
|
||||
#: service/rpc/io_stream.go:125
|
||||
msgid "timeout: user connection not established"
|
||||
msgstr "tiempo de espera agotado: no se pudo establecer conexión con el usuario"
|
||||
|
||||
#: service/rpc/io_stream.go:128
|
||||
msgid "timeout: agent connection not established"
|
||||
msgstr "tiempo de espera agotado: no se pudo establecer conexión con agent"
|
||||
|
||||
#: service/rpc/nezha.go:58
|
||||
msgid "Scheduled Task Executed Successfully"
|
||||
msgstr "tarea programada ejecutada con éxito"
|
||||
|
||||
#: service/rpc/nezha.go:62
|
||||
msgid "Scheduled Task Executed Failed"
|
||||
msgstr "falló la ejecución de la tarea programada"
|
||||
|
||||
#: service/rpc/nezha.go:217
|
||||
msgid "IP Changed"
|
||||
msgstr "IP cambiada"
|
||||
|
||||
#: service/singleton/alertsentinel.go:159
|
||||
msgid "Incident"
|
||||
msgstr "Incidente"
|
||||
|
||||
#: service/singleton/alertsentinel.go:169
|
||||
msgid "Resolved"
|
||||
msgstr "Resuelto"
|
||||
|
||||
#: service/singleton/crontask.go:53
|
||||
msgid "Tasks failed to register: ["
|
||||
msgstr "Las tareas no se pudieron registrar: ["
|
||||
|
||||
#: service/singleton/crontask.go:60
|
||||
msgid ""
|
||||
"] These tasks will not execute properly. Fix them in the admin dashboard."
|
||||
msgstr ""
|
||||
"] Estas tareas no se ejecutarán correctamente. Corríjalas en el dashboard de "
|
||||
"administración."
|
||||
|
||||
#: service/singleton/crontask.go:146 service/singleton/crontask.go:171
|
||||
#, c-format
|
||||
msgid "[Task failed] %s: server %s is offline and cannot execute the task"
|
||||
msgstr ""
|
||||
"[Tarea fallida] %s: el servidor %s está fuera de línea y no puede ejecutar "
|
||||
"la tarea"
|
||||
|
||||
#: service/singleton/servicesentinel.go:439
|
||||
#, c-format
|
||||
msgid "[Latency] %s %2f > %2f, Reporter: %s"
|
||||
msgstr "[Latencia] %s %2f > %2f, Reportado por: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:446
|
||||
#, c-format
|
||||
msgid "[Latency] %s %2f < %2f, Reporter: %s"
|
||||
msgstr "[Latencia] %s %2f < %2f, Reportado por: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:472
|
||||
#, c-format
|
||||
msgid "[%s] %s Reporter: %s, Error: %s"
|
||||
msgstr "[%s] %s Reportado por: %s, Error: %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:515
|
||||
#, c-format
|
||||
msgid "[TLS] Fetch cert info failed, Reporter: %s, Error: %s"
|
||||
msgstr ""
|
||||
"[TLS] Error al obtener información del certificado, Reportado por: %s, Error:"
|
||||
" %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:555
|
||||
#, c-format
|
||||
msgid "The TLS certificate will expire within seven days. Expiration time: %s"
|
||||
msgstr ""
|
||||
"El certificado TLS expirará en los próximos siete días. Fecha de expiración: "
|
||||
"%s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:568
|
||||
#, c-format
|
||||
msgid ""
|
||||
"TLS certificate changed, old: issuer %s, expires at %s; new: issuer %s, "
|
||||
"expires at %s"
|
||||
msgstr ""
|
||||
"El certificado TLS ha cambiado. Antiguo: emisor %s, expira en %s; Nuevo: "
|
||||
"emisor %s, expira en %s"
|
||||
|
||||
#: service/singleton/servicesentinel.go:604
|
||||
msgid "No Data"
|
||||
msgstr "Sin datos"
|
||||
|
||||
#: service/singleton/servicesentinel.go:606
|
||||
msgid "Good"
|
||||
msgstr "Bueno"
|
||||
|
||||
#: service/singleton/servicesentinel.go:608
|
||||
msgid "Low Availability"
|
||||
msgstr "Baja disponibilidad"
|
||||
|
||||
#: service/singleton/servicesentinel.go:610
|
||||
msgid "Down"
|
||||
msgstr "Fallo"
|
@ -2,6 +2,7 @@ package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"strings"
|
||||
|
||||
petname "github.com/dustinkirkland/golang-petname"
|
||||
@ -36,10 +37,14 @@ func (a *authHandler) Check(ctx context.Context) (uint64, error) {
|
||||
|
||||
ip, _ := ctx.Value(model.CtxKeyRealIP{}).(string)
|
||||
|
||||
if clientSecret != singleton.Conf.AgentSecretKey {
|
||||
singleton.UserLock.RLock()
|
||||
userId, ok := singleton.AgentSecretToUserId[clientSecret]
|
||||
if !ok && subtle.ConstantTimeCompare([]byte(clientSecret), []byte(singleton.Conf.AgentSecretKey)) != 1 {
|
||||
singleton.UserLock.RUnlock()
|
||||
model.BlockIP(singleton.DB, ip, model.WAFBlockReasonTypeAgentAuthFail)
|
||||
return 0, status.Error(codes.Unauthenticated, "客户端认证失败")
|
||||
}
|
||||
singleton.UserLock.RUnlock()
|
||||
|
||||
model.ClearIP(singleton.DB, ip)
|
||||
|
||||
@ -53,21 +58,26 @@ func (a *authHandler) Check(ctx context.Context) (uint64, error) {
|
||||
}
|
||||
|
||||
singleton.ServerLock.RLock()
|
||||
defer singleton.ServerLock.RUnlock()
|
||||
|
||||
clientID, hasID := singleton.ServerUUIDToID[clientUUID]
|
||||
singleton.ServerLock.RUnlock()
|
||||
|
||||
if !hasID {
|
||||
s := model.Server{UUID: clientUUID, Name: petname.Generate(2, "-")}
|
||||
s := model.Server{UUID: clientUUID, Name: petname.Generate(2, "-"), Common: model.Common{
|
||||
UserID: userId,
|
||||
}}
|
||||
if err := singleton.DB.Create(&s).Error; err != nil {
|
||||
return 0, status.Error(codes.Unauthenticated, err.Error())
|
||||
}
|
||||
s.Host = &model.Host{}
|
||||
s.State = &model.HostState{}
|
||||
s.GeoIP = &model.GeoIP{}
|
||||
// generate a random silly server name
|
||||
|
||||
singleton.ServerLock.Lock()
|
||||
singleton.ServerList[s.ID] = &s
|
||||
singleton.ServerUUIDToID[clientUUID] = s.ID
|
||||
singleton.ServerLock.Unlock()
|
||||
singleton.ReSortServer()
|
||||
|
||||
clientID = s.ID
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,10 @@ var (
|
||||
|
||||
func initDDNS() {
|
||||
DB.Find(&DDNSList)
|
||||
DDNSCacheLock.Lock()
|
||||
DDNSCache = make(map[uint64]*model.DDNSProfile)
|
||||
for i := 0; i < len(DDNSList); i++ {
|
||||
DDNSCache[DDNSList[i].ID] = DDNSList[i]
|
||||
}
|
||||
DDNSCacheLock.Unlock()
|
||||
|
||||
OnNameserverUpdate()
|
||||
}
|
||||
|
@ -2,14 +2,14 @@
|
||||
name: "OfficialAdmin"
|
||||
repository: "https://github.com/nezhahq/admin-frontend"
|
||||
author: "nezhahq"
|
||||
version: "v1.2.0"
|
||||
version: "v1.2.2"
|
||||
isadmin: true
|
||||
isofficial: true
|
||||
- path: "user-dist"
|
||||
name: "Official"
|
||||
repository: "https://github.com/hamster1963/nezha-dash-v1"
|
||||
author: "hamster1963"
|
||||
version: "v1.3.5"
|
||||
version: "v1.4.5"
|
||||
isofficial: true
|
||||
- path: "nazhua-dist"
|
||||
name: "Nazhua"
|
||||
|
@ -19,8 +19,6 @@ var (
|
||||
|
||||
func initNAT() {
|
||||
DB.Find(&NATList)
|
||||
NATCacheRwLock.Lock()
|
||||
defer NATCacheRwLock.Unlock()
|
||||
NATCache = make(map[string]*model.NAT)
|
||||
for i := 0; i < len(NATList); i++ {
|
||||
NATCache[NATList[i].Domain] = NATList[i]
|
||||
|
@ -30,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
// InitNotification 初始化 GroupID <-> ID <-> Notification 的映射
|
||||
func InitNotification() {
|
||||
func initNotification() {
|
||||
NotificationList = make(map[uint64]map[uint64]*model.Notification)
|
||||
NotificationIDToGroups = make(map[uint64]map[uint64]struct{})
|
||||
NotificationGroup = make(map[uint64]string)
|
||||
@ -38,9 +38,7 @@ func InitNotification() {
|
||||
|
||||
// loadNotifications 从 DB 初始化通知方式相关参数
|
||||
func loadNotifications() {
|
||||
InitNotification()
|
||||
NotificationsLock.Lock()
|
||||
|
||||
initNotification()
|
||||
groupNotifications := make(map[uint64][]uint64)
|
||||
var ngn []model.NotificationGroupNotification
|
||||
if err := DB.Find(&ngn).Error; err != nil {
|
||||
@ -74,8 +72,6 @@ func loadNotifications() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationsLock.Unlock()
|
||||
}
|
||||
|
||||
func UpdateNotificationList() {
|
||||
|
@ -192,13 +192,6 @@ func (ss *ServiceSentinel) loadServiceHistory() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ss.serviceResponseDataStoreLock.Lock()
|
||||
defer ss.serviceResponseDataStoreLock.Unlock()
|
||||
ss.monthlyStatusLock.Lock()
|
||||
defer ss.monthlyStatusLock.Unlock()
|
||||
ss.ServicesLock.Lock()
|
||||
defer ss.ServicesLock.Unlock()
|
||||
|
||||
for i := 0; i < len(services); i++ {
|
||||
task := *services[i]
|
||||
// 通过cron定时将服务监控任务传递给任务调度管道
|
||||
|
@ -40,6 +40,7 @@ func InitTimezoneAndCache() {
|
||||
|
||||
// LoadSingleton 加载子服务并执行
|
||||
func LoadSingleton() {
|
||||
initUser() // 加载用户ID绑定表
|
||||
initI18n() // 加载本地化服务
|
||||
loadNotifications() // 加载通知服务
|
||||
loadServers() // 加载服务器列表
|
||||
@ -79,8 +80,8 @@ func InitDBFromPath(path string) {
|
||||
}
|
||||
err = DB.AutoMigrate(model.Server{}, model.User{}, model.ServerGroup{}, model.NotificationGroup{},
|
||||
model.Notification{}, model.AlertRule{}, model.Service{}, model.NotificationGroupNotification{},
|
||||
model.ServiceHistory{}, model.Cron{}, model.Transfer{}, model.ServerGroupServer{}, model.UserGroup{},
|
||||
model.UserGroupUser{}, model.NAT{}, model.DDNSProfile{}, model.NotificationGroupNotification{},
|
||||
model.ServiceHistory{}, model.Cron{}, model.Transfer{}, model.ServerGroupServer{},
|
||||
model.NAT{}, model.DDNSProfile{}, model.NotificationGroupNotification{},
|
||||
model.WAF{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
54
service/singleton/user.go
Normal file
54
service/singleton/user.go
Normal file
@ -0,0 +1,54 @@
|
||||
package singleton
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
)
|
||||
|
||||
var (
|
||||
UserIdToAgentSecret map[uint64]string
|
||||
AgentSecretToUserId map[string]uint64
|
||||
|
||||
UserLock sync.RWMutex
|
||||
)
|
||||
|
||||
func initUser() {
|
||||
UserIdToAgentSecret = make(map[uint64]string)
|
||||
AgentSecretToUserId = make(map[string]uint64)
|
||||
|
||||
var users []model.User
|
||||
DB.Find(&users)
|
||||
|
||||
for _, u := range users {
|
||||
UserIdToAgentSecret[u.ID] = u.AgentSecret
|
||||
AgentSecretToUserId[u.AgentSecret] = u.ID
|
||||
}
|
||||
}
|
||||
|
||||
func OnUserUpdate(u *model.User) {
|
||||
UserLock.Lock()
|
||||
defer UserLock.Unlock()
|
||||
|
||||
if u == nil {
|
||||
return
|
||||
}
|
||||
|
||||
UserIdToAgentSecret[u.ID] = u.AgentSecret
|
||||
AgentSecretToUserId[u.AgentSecret] = u.ID
|
||||
}
|
||||
|
||||
func OnUserDelete(id []uint64) {
|
||||
UserLock.Lock()
|
||||
defer UserLock.Unlock()
|
||||
|
||||
if len(id) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, uid := range id {
|
||||
secret := UserIdToAgentSecret[uid]
|
||||
delete(AgentSecretToUserId, secret)
|
||||
delete(UserIdToAgentSecret, uid)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user