mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 08:00:53 +00:00
fix: avoid license required before login (#12626)
This commit is contained in:
committed by
zhengkunwang223
parent
d55982bde0
commit
eb527857f3
@@ -461,6 +461,28 @@ func (b *BaseApi) UpdateCurrentUser(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
// @Summary Reset system password expired
|
||||
// @Accept json
|
||||
// @Param request body dto.PasswordUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /core/auth/expired/reset [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"重置过期密码","formatEN":"reset an expired Password"}
|
||||
func (b *BaseApi) ResetPassword(c *gin.Context) {
|
||||
var req dto.PasswordUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := xpack.AuthProvider.HandlePasswordExpired(c, req.OldPassword, req.NewPassword); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func saveLoginLogs(c *gin.Context, err error) {
|
||||
var logs model.LoginLog
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/xpack"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -338,28 +337,6 @@ func (b *BaseApi) UpdatePort(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Reset system password expired
|
||||
// @Accept json
|
||||
// @Param request body dto.PasswordUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /core/settings/expired/handle [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"重置过期密码","formatEN":"reset an expired Password"}
|
||||
func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
|
||||
var req dto.PasswordUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := xpack.AuthProvider.HandlePasswordExpired(c, req.OldPassword, req.NewPassword); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
func (b *BaseApi) ReloadSSL(c *gin.Context) {
|
||||
clientIP := c.ClientIP()
|
||||
if clientIP != "127.0.0.1" {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/buserr"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
@@ -126,7 +127,7 @@ func runRemoteShellScript(url string, args ...string) error {
|
||||
if statusCode < http.StatusOK || statusCode >= http.StatusMultipleChoices {
|
||||
return fmt.Errorf("download script failed, status code: %d", statusCode)
|
||||
}
|
||||
_, err = cmd.NewCommandMgr().RunPipe(cmd.PipeCommand{
|
||||
_, err = cmd.NewCommandMgr(cmd.WithOutputFile(os.DevNull)).RunPipe(cmd.PipeCommand{
|
||||
Name: "sh",
|
||||
Args: append([]string{"-s"}, args...),
|
||||
Stdin: bytes.NewReader(script),
|
||||
|
||||
@@ -4,7 +4,7 @@ base:
|
||||
is_demo: false
|
||||
is_offline: false
|
||||
is_fxplay: false
|
||||
is_xpackee: false
|
||||
is_xpackee: true
|
||||
port: 9999
|
||||
username: admin
|
||||
password: admin123
|
||||
|
||||
@@ -16,9 +16,11 @@ import (
|
||||
func PasswordExpired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api/v2/core/auth") ||
|
||||
c.Request.URL.Path == "/api/v2/core/settings/expired/handle" ||
|
||||
c.Request.URL.Path == "/api/v2/core/settings/search" ||
|
||||
c.Request.URL.Path == "/api/v2/core/settings/search/base" {
|
||||
c.Request.URL.Path == "/api/v2/core/settings/search/base" ||
|
||||
c.Request.URL.Path == "/api/v2/core/xpackee/licenses/info" ||
|
||||
c.Request.URL.Path == "/api/v2/core/xpackee/licenses/status" ||
|
||||
c.Request.URL.Path == "/api/v2/core/xpackee/licenses/upload" {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,14 +26,17 @@ func (s *BaseRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
|
||||
authRouter.POST("/mfa", baseApi.LoadMFA)
|
||||
authRouter.POST("/mfa/bind", baseApi.MFABind)
|
||||
|
||||
authRouter.POST("/passkey/register/begin", baseApi.PasskeyRegisterBegin)
|
||||
authRouter.POST("/passkey/register/finish", baseApi.PasskeyRegisterFinish)
|
||||
authRouter.GET("/passkey/list", baseApi.PasskeyList)
|
||||
authRouter.POST("/passkey/del", baseApi.PasskeyDelete)
|
||||
|
||||
authRouter.POST("/api/generate", baseApi.GenerateApiKey)
|
||||
authRouter.POST("/api/update", baseApi.UpdateApiConfig)
|
||||
|
||||
authRouter.GET("/current", baseApi.GetCurrentUser)
|
||||
authRouter.POST("/current/update", baseApi.UpdateCurrentUser)
|
||||
authRouter.POST("/expired/reset", baseApi.ResetPassword)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
noAuthRouter := Router.Group("settings")
|
||||
baseApi := v2.ApiGroupApp.BaseApi
|
||||
{
|
||||
router.POST("/search", baseApi.GetSettingInfo)
|
||||
router.POST("/search/base", baseApi.GetSettingBaseInfo)
|
||||
|
||||
settingRouter.POST("/by", baseApi.GetSettingByKey)
|
||||
settingRouter.POST("/search", baseApi.GetSettingInfo)
|
||||
settingRouter.POST("/terminal/search", baseApi.GetTerminalSettingInfo)
|
||||
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
|
||||
settingRouter.POST("/update", baseApi.UpdateSetting)
|
||||
|
||||
@@ -94,7 +94,15 @@ class RequestHttp {
|
||||
}
|
||||
if (data.code == ResultEnum.ERRXPACKEE) {
|
||||
globalStore.isXpackEELicensed = false;
|
||||
router.push({ name: 'XpackEELicenseRequired' });
|
||||
const routeName = router.currentRoute.value.name;
|
||||
if (
|
||||
globalStore.isLogin &&
|
||||
routeName !== 'entrance' &&
|
||||
routeName !== 'login' &&
|
||||
routeName !== 'XpackEELicenseRequired'
|
||||
) {
|
||||
router.push({ name: 'XpackEELicenseRequired' });
|
||||
}
|
||||
return Promise.reject(data);
|
||||
}
|
||||
if (data.code == ResultEnum.NodeUnBind) {
|
||||
|
||||
@@ -90,4 +90,8 @@ export namespace Login {
|
||||
ipWhiteList: string;
|
||||
apiKeyValidityTime: string;
|
||||
}
|
||||
export interface PasswordUpdate {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,10 +152,6 @@ export namespace Setting {
|
||||
key: string;
|
||||
sslID: number;
|
||||
}
|
||||
export interface PasswordUpdate {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
}
|
||||
export interface PortUpdate {
|
||||
serverPort: number;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@ export const getWelcomePage = () => {
|
||||
export const getUserInfo = () => {
|
||||
return http.get<Login.AuthInfo>('/core/auth/current');
|
||||
};
|
||||
export const updateUserInfo = (params: Login.AuthInfoUpdate) => {
|
||||
let request = deepCopy(params) as Login.AuthInfoUpdate;
|
||||
if (request.oldPassword) {
|
||||
request.oldPassword = Base64.encode(request.oldPassword);
|
||||
}
|
||||
if (request.password) {
|
||||
request.password = Base64.encode(request.password);
|
||||
}
|
||||
return http.post<any>('/core/auth/current/update', request);
|
||||
};
|
||||
|
||||
export const loadMFA = (params: Login.MFARequest) => {
|
||||
return http.post<Login.MFAInfo>(`/core/auth/mfa`, params);
|
||||
};
|
||||
@@ -66,13 +77,6 @@ export const passkeyDelete = (id: string) => {
|
||||
return http.post(`/core/auth/passkey/del`, { id });
|
||||
};
|
||||
|
||||
export const updateUserInfo = (params: Login.AuthInfoUpdate) => {
|
||||
let request = deepCopy(params) as Login.AuthInfoUpdate;
|
||||
if (request.oldPassword) {
|
||||
request.oldPassword = Base64.encode(request.oldPassword);
|
||||
}
|
||||
if (request.password) {
|
||||
request.password = Base64.encode(request.password);
|
||||
}
|
||||
return http.post<any>('/core/auth/current/update', request);
|
||||
export const handleExpired = (param: Login.PasswordUpdate) => {
|
||||
return http.post(`/core/auth/expired/reset`, param);
|
||||
};
|
||||
|
||||
@@ -148,9 +148,6 @@ export const updateProxy = (params: Setting.ProxyUpdate) => {
|
||||
request.proxyType = request.proxyType === 'close' ? '' : request.proxyType;
|
||||
return http.post(`/core/settings/proxy/update`, request);
|
||||
};
|
||||
export const updatePassword = (param: Setting.PasswordUpdate) => {
|
||||
return http.post(`/core/settings/password/update`, param);
|
||||
};
|
||||
export const loadInterfaceAddr = () => {
|
||||
return http.get(`/core/settings/interface`);
|
||||
};
|
||||
@@ -169,9 +166,6 @@ export const loadSSLInfo = () => {
|
||||
export const downloadSSL = () => {
|
||||
return http.download<any>(`/core/settings/ssl/download`);
|
||||
};
|
||||
export const handleExpired = (param: Setting.PasswordUpdate) => {
|
||||
return http.post(`/core/settings/expired/handle`, param);
|
||||
};
|
||||
export const getAppStoreConfig = (node?: string) => {
|
||||
const params = node ? `?operateNode=${node}` : '';
|
||||
return http.get<App.AppStoreConfig>(`/core/settings/apps/store/config${params}`);
|
||||
|
||||
@@ -271,9 +271,9 @@ const logout = () => {
|
||||
})
|
||||
.then(async () => {
|
||||
await logOutApi();
|
||||
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
globalStore.setLogStatus(false);
|
||||
globalStore.clearAuthInfo();
|
||||
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
@@ -855,9 +855,9 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = false;
|
||||
open.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
globalStore.setLogStatus(false);
|
||||
globalStore.clearAuthInfo();
|
||||
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
|
||||
@@ -3,57 +3,36 @@ import NProgress from '@/config/nprogress';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { AxiosCanceler } from '@/api/helper/axios-cancel';
|
||||
import { hasRouteAccess } from '@/utils/rbac';
|
||||
import { loadProductProFromDB } from '@/utils/xpack';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError } from '@/utils/message';
|
||||
|
||||
const axiosCanceler = new AxiosCanceler();
|
||||
|
||||
let isRedirecting = false;
|
||||
let xpackEELoading: Promise<boolean> | null = null;
|
||||
let licenseStatusLoading: Promise<boolean> | null = null;
|
||||
const xpackEELicenseCheckWhiteList = ['XpackEELicenseRequired', 'entrance', 'login', 'Expired'];
|
||||
|
||||
const loadXpackEEStatus = async () => {
|
||||
if (!xpackEELoading) {
|
||||
xpackEELoading = fetch('/api/v2/core/auth/setting', {
|
||||
credentials: 'include',
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const globalStore = GlobalStore();
|
||||
globalStore.isXpackEE = !!res?.data?.isXpackEE;
|
||||
return globalStore.isXpackEE;
|
||||
})
|
||||
.catch(() => GlobalStore().isXpackEE)
|
||||
.finally(() => {
|
||||
xpackEELoading = null;
|
||||
});
|
||||
}
|
||||
return xpackEELoading;
|
||||
const clearLicenseStatus = () => {
|
||||
const globalStore = GlobalStore();
|
||||
globalStore.isXpackEELicensed = false;
|
||||
globalStore.isXpackEELicenseLoaded = false;
|
||||
};
|
||||
|
||||
const loadXpackEELicenseStatus = async () => {
|
||||
if (!licenseStatusLoading) {
|
||||
licenseStatusLoading = fetch('/api/v2/core/xpackee/licenses/status', {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
CurrentNode: encodeURIComponent(GlobalStore().currentNode),
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => res?.data?.status === 'Bound')
|
||||
.catch(() => false)
|
||||
.finally(() => {
|
||||
licenseStatusLoading = null;
|
||||
});
|
||||
}
|
||||
return licenseStatusLoading;
|
||||
const clearLoginStatus = () => {
|
||||
const globalStore = GlobalStore();
|
||||
globalStore.setLogStatus(false);
|
||||
globalStore.clearAuthInfo();
|
||||
clearLicenseStatus();
|
||||
};
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
axiosCanceler.removeAllPending();
|
||||
const globalStore = GlobalStore();
|
||||
if (to.name !== 'entrance' && to.name !== 'XpackEELicenseRequired' && !globalStore.isLogin) {
|
||||
if (!globalStore.isLogin) {
|
||||
clearLoginStatus();
|
||||
}
|
||||
if (to.name !== 'entrance' && !globalStore.isLogin) {
|
||||
next({
|
||||
name: 'entrance',
|
||||
params: to.params,
|
||||
@@ -73,19 +52,11 @@ router.beforeEach(async (to, from, next) => {
|
||||
NProgress.done();
|
||||
return;
|
||||
}
|
||||
if (globalStore.isLogin && to.name !== 'login') {
|
||||
await loadXpackEEStatus();
|
||||
}
|
||||
if (
|
||||
globalStore.isLogin &&
|
||||
globalStore.isXpackEE &&
|
||||
to.name !== 'XpackEELicenseRequired' &&
|
||||
to.name !== 'entrance' &&
|
||||
to.name !== 'login'
|
||||
) {
|
||||
const licensed = globalStore.isXpackEELicensed || (await loadXpackEELicenseStatus());
|
||||
globalStore.isXpackEELicensed = licensed;
|
||||
if (!licensed) {
|
||||
if (globalStore.isLogin && globalStore.isXpackEE && !xpackEELicenseCheckWhiteList.includes(String(to.name))) {
|
||||
if (!globalStore.isXpackEELicenseLoaded) {
|
||||
await loadProductProFromDB();
|
||||
}
|
||||
if (!globalStore.isXpackEELicensed) {
|
||||
next({ name: 'XpackEELicenseRequired', query: { code: String(to.params.code || '') } });
|
||||
NProgress.done();
|
||||
return;
|
||||
@@ -100,7 +71,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
NProgress.done();
|
||||
return;
|
||||
}
|
||||
if (globalStore.isXpackEELicensed) {
|
||||
if (!globalStore.isXpackEE || globalStore.isXpackEELicensed) {
|
||||
next({ name: 'home' });
|
||||
NProgress.done();
|
||||
return;
|
||||
|
||||
@@ -68,6 +68,7 @@ export interface GlobalState {
|
||||
productProExpires: number;
|
||||
isMasterProductPro: boolean;
|
||||
isXpackEELicensed: boolean;
|
||||
isXpackEELicenseLoaded: boolean;
|
||||
// multi-node
|
||||
masterAlias: string;
|
||||
currentNode: string;
|
||||
|
||||
@@ -65,6 +65,7 @@ const GlobalStore = defineStore({
|
||||
productProExpires: 0,
|
||||
isMasterProductPro: false,
|
||||
isXpackEELicensed: false,
|
||||
isXpackEELicenseLoaded: false,
|
||||
// multi-node
|
||||
masterAlias: '',
|
||||
currentNode: 'local',
|
||||
|
||||
@@ -84,6 +84,7 @@ const loadDataFromDB = async () => {
|
||||
export async function loadProductProFromDB() {
|
||||
const globalStore = getGlobalStore();
|
||||
if (!globalStore.isXpackEE) {
|
||||
globalStore.isXpackEELicenseLoaded = true;
|
||||
const res = await getLicenseStatus();
|
||||
if (!res || !res.data) {
|
||||
globalStore.isProductPro = false;
|
||||
@@ -96,6 +97,7 @@ export async function loadProductProFromDB() {
|
||||
return;
|
||||
}
|
||||
const res = await getXpackEELicenseStatus();
|
||||
globalStore.isXpackEELicenseLoaded = true;
|
||||
if (!res || !res.data) {
|
||||
globalStore.isXpackEELicensed = false;
|
||||
} else {
|
||||
@@ -106,6 +108,7 @@ export async function loadProductProFromDB() {
|
||||
export async function loadMasterProductProFromDB() {
|
||||
const globalStore = getGlobalStore();
|
||||
if (!globalStore.isXpackEE) {
|
||||
globalStore.isXpackEELicenseLoaded = true;
|
||||
const res = await getMasterLicenseStatus();
|
||||
if (!res || !res.data) {
|
||||
globalStore.isMasterProductPro = false;
|
||||
@@ -114,6 +117,7 @@ export async function loadMasterProductProFromDB() {
|
||||
}
|
||||
} else {
|
||||
const res = await getXpackEELicenseStatus();
|
||||
globalStore.isXpackEELicenseLoaded = true;
|
||||
if (!res || !res.data) {
|
||||
globalStore.isXpackEELicensed = false;
|
||||
} else {
|
||||
|
||||
@@ -630,6 +630,7 @@ const getSetting = async () => {
|
||||
globalStore.isFxplay = isFxplay.value;
|
||||
globalStore.isOffLine = res.data.isOffLine;
|
||||
globalStore.isXpackEE = res.data.isXpackEE;
|
||||
globalStore.isXpackEELicenseLoaded = !res.data.isXpackEE;
|
||||
globalStore.ignoreCaptcha = !res.data.needCaptcha;
|
||||
passkeySetting.value = res.data.passkeySetting;
|
||||
if (!globalStore.ignoreCaptcha) {
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, reactive } from 'vue';
|
||||
import { getSettingBaseInfo, handleExpired } from '@/api/modules/setting';
|
||||
import { getSettingBaseInfo } from '@/api/modules/setting';
|
||||
import { handleExpired } from '@/api/modules/auth';
|
||||
import { ElForm } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
|
||||
@@ -104,6 +104,7 @@ const loadImage = (name: string) => {
|
||||
const loadLoginTheme = async () => {
|
||||
const res = await getLoginSetting();
|
||||
globalStore.isXpackEE = res.data.isXpackEE;
|
||||
globalStore.isXpackEELicenseLoaded = !res.data.isXpackEE;
|
||||
globalStore.isIntl = res.data.isIntl;
|
||||
globalStore.isFxplay = res.data.isFxplay;
|
||||
globalStore.isOffLine = res.data.isOffLine;
|
||||
@@ -125,7 +126,9 @@ const loadLoginTheme = async () => {
|
||||
adjustColorToRGBA(loginBtnLinkColor.value, 30, 15),
|
||||
);
|
||||
if (!globalStore.isXpackEE) {
|
||||
router.replace({ name: 'entrance', params: { code: globalStore.entrance } });
|
||||
router.replace(
|
||||
globalStore.isLogin ? { name: 'home' } : { name: 'entrance', params: { code: globalStore.entrance } },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,6 +158,7 @@ const loadBackground = async () => {
|
||||
|
||||
const loadLicenseInfo = async () => {
|
||||
const res = await getXpackEELicense();
|
||||
globalStore.isXpackEELicenseLoaded = true;
|
||||
licenseInfo.deviceID = res.data.deviceID;
|
||||
if (res.data.status === 'Bound') {
|
||||
globalStore.isXpackEELicensed = true;
|
||||
|
||||
Reference in New Issue
Block a user