mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-05 05:32:07 +03:00
fix(api-token): keep a token's scope when -getApiToken regenerates it, add -tokenScope (#6700)
* fix(api-token): keep a token's scope when the CLI regenerates it RecreateByName deleted the named row and created a new one without a Scope, so the insert took the column default of admin. Since -tokenName lets the CLI regenerate any token, rotating a monitor or node-sync token silently turned it into a full-access one. The replacement now takes the scope of the row it replaces, and a new name still gets admin as before. A stored scope this build does not know, as after a downgrade, fails the rotation and leaves the row alone instead of guessing. Assisted-by: Claude Code:claude-opus-5-5 (mostly) * feat(cli): let -getApiToken choose the scope of the token it issues -tokenScope sets the scope on both branches of -getApiToken: the token minted on a fresh panel and the one regenerated on a populated panel. Without the flag a regenerated token keeps its scope and a new one gets admin, so every existing invocation, install.sh included, behaves as before. An unknown scope is refused before anything is deleted, so a typo cannot revoke the token it meant to rotate. Assisted-by: Claude Code:claude-opus-5-5 (mostly) * fix(api-token): keep a token's expiry when the CLI regenerates it RecreateByName built the replacement row with ExpiresAt 0, so running `x-ui setting -getApiToken -tokenName <name>` on a token issued through the API with a deadline handed back one that never expires, and said nothing about it - the same silent widening this branch fixed for scope. The replacement now carries the replaced row's ExpiresAt. A token whose deadline has already passed is refused instead of rotated, since keeping the deadline would mint a dead token and dropping it would revive an expired credential without limit; the expired row is left untouched. --------- Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -498,7 +498,7 @@ func GetListenIP(getListen bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func GetApiToken(getApiToken bool, tokenName string) {
|
||||
func GetApiToken(getApiToken bool, tokenName, tokenScope string) {
|
||||
if !getApiToken {
|
||||
return
|
||||
}
|
||||
@@ -526,7 +526,7 @@ func GetApiToken(getApiToken bool, tokenName string) {
|
||||
if rotated == "" {
|
||||
rotated = cliFallbackTokenName
|
||||
}
|
||||
created, err := apiTokenService.RecreateByName(rotated)
|
||||
created, err := apiTokenService.RecreateByName(rotated, tokenScope)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to create a fallback API token:", err)
|
||||
return
|
||||
@@ -538,7 +538,7 @@ func GetApiToken(getApiToken bool, tokenName string) {
|
||||
if name == "" {
|
||||
name = installTokenName
|
||||
}
|
||||
created, err := apiTokenService.Create(name, "", 0)
|
||||
created, err := apiTokenService.Create(name, tokenScope, 0)
|
||||
if err != nil {
|
||||
fmt.Println("create apiToken failed, error info:", err)
|
||||
return
|
||||
@@ -621,6 +621,7 @@ func main() {
|
||||
var getCert bool
|
||||
var getApiToken bool
|
||||
var tokenName string
|
||||
var tokenScope string
|
||||
var resetTwoFactor bool
|
||||
settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
|
||||
settingCmd.BoolVar(&show, "show", false, "Display current settings")
|
||||
@@ -634,6 +635,7 @@ func main() {
|
||||
settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings")
|
||||
settingCmd.BoolVar(&getApiToken, "getApiToken", false, "Print an API token for CLI use, regenerating it and invalidating the previous one; on a panel with no tokens yet it mints one instead")
|
||||
settingCmd.StringVar(&tokenName, "tokenName", "", "Name of the token -getApiToken acts on (default: "+cliFallbackTokenName+", or "+installTokenName+" on a panel with no tokens)")
|
||||
settingCmd.StringVar(&tokenScope, "tokenScope", "", "Scope of the token -getApiToken issues: admin, monitor or node-sync (default: the scope of the token it replaces, or admin for a new one)")
|
||||
settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel")
|
||||
settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel")
|
||||
settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot")
|
||||
@@ -732,7 +734,7 @@ func main() {
|
||||
GetCertificate(getCert)
|
||||
}
|
||||
if getApiToken {
|
||||
GetApiToken(getApiToken, tokenName)
|
||||
GetApiToken(getApiToken, tokenName, tokenScope)
|
||||
}
|
||||
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
|
||||
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
|
||||
|
||||
Reference in New Issue
Block a user