mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-10-31 04:12:51 +00:00 
			
		
		
		
	api (#3434)
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
		
			
				
	
				Release 3X-UI / build (386) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (amd64) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (arm64) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (armv5) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (armv6) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (armv7) (push) Waiting to run
				
			
		
			
				
	
				Release 3X-UI / build (s390x) (push) Waiting to run
				
			
		
		
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	Release 3X-UI / build (386) (push) Waiting to run
				
			Release 3X-UI / build (amd64) (push) Waiting to run
				
			Release 3X-UI / build (arm64) (push) Waiting to run
				
			Release 3X-UI / build (armv5) (push) Waiting to run
				
			Release 3X-UI / build (armv6) (push) Waiting to run
				
			Release 3X-UI / build (armv7) (push) Waiting to run
				
			Release 3X-UI / build (s390x) (push) Waiting to run
				
			This commit is contained in:
		
							parent
							
								
									18d74d54ca
								
							
						
					
					
						commit
						fe9f0d1d0e
					
				
					 14 changed files with 141 additions and 106 deletions
				
			
		|  | @ -9,6 +9,7 @@ import ( | |||
| type APIController struct { | ||||
| 	BaseController | ||||
| 	inboundController *InboundController | ||||
| 	serverController  *ServerController | ||||
| 	Tgbot             service.Tgbot | ||||
| } | ||||
| 
 | ||||
|  | @ -19,43 +20,22 @@ func NewAPIController(g *gin.RouterGroup) *APIController { | |||
| } | ||||
| 
 | ||||
| func (a *APIController) initRouter(g *gin.RouterGroup) { | ||||
| 	g = g.Group("/panel/api/inbounds") | ||||
| 	g.Use(a.checkLogin) | ||||
| 	// Main API group
 | ||||
| 	api := g.Group("/panel/api") | ||||
| 	api.Use(a.checkLogin) | ||||
| 
 | ||||
| 	a.inboundController = NewInboundController(g) | ||||
| 	// Inbounds API
 | ||||
| 	inbounds := api.Group("/inbounds") | ||||
| 	a.inboundController = NewInboundController(inbounds) | ||||
| 
 | ||||
| 	inboundRoutes := []struct { | ||||
| 		Method  string | ||||
| 		Path    string | ||||
| 		Handler gin.HandlerFunc | ||||
| 	}{ | ||||
| 		{"GET", "/createbackup", a.createBackup}, | ||||
| 		{"GET", "/list", a.inboundController.getInbounds}, | ||||
| 		{"GET", "/get/:id", a.inboundController.getInbound}, | ||||
| 		{"GET", "/getClientTraffics/:email", a.inboundController.getClientTraffics}, | ||||
| 		{"GET", "/getClientTrafficsById/:id", a.inboundController.getClientTrafficsById}, | ||||
| 		{"POST", "/add", a.inboundController.addInbound}, | ||||
| 		{"POST", "/del/:id", a.inboundController.delInbound}, | ||||
| 		{"POST", "/update/:id", a.inboundController.updateInbound}, | ||||
| 		{"POST", "/clientIps/:email", a.inboundController.getClientIps}, | ||||
| 		{"POST", "/clearClientIps/:email", a.inboundController.clearClientIps}, | ||||
| 		{"POST", "/addClient", a.inboundController.addInboundClient}, | ||||
| 		{"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient}, | ||||
| 		{"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient}, | ||||
| 		{"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic}, | ||||
| 		{"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics}, | ||||
| 		{"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics}, | ||||
| 		{"POST", "/delDepletedClients/:id", a.inboundController.delDepletedClients}, | ||||
| 		{"POST", "/onlines", a.inboundController.onlines}, | ||||
| 		{"POST", "/lastOnline", a.inboundController.lastOnline}, | ||||
| 		{"POST", "/updateClientTraffic/:email", a.inboundController.updateClientTraffic}, | ||||
| 	} | ||||
| 	// Server API
 | ||||
| 	server := api.Group("/server") | ||||
| 	a.serverController = NewServerController(server) | ||||
| 
 | ||||
| 	for _, route := range inboundRoutes { | ||||
| 		g.Handle(route.Method, route.Path, route.Handler) | ||||
| 	} | ||||
| 	// Extra routes
 | ||||
| 	api.GET("/backuptotgbot", a.BackuptoTgbot) | ||||
| } | ||||
| 
 | ||||
| func (a *APIController) createBackup(c *gin.Context) { | ||||
| func (a *APIController) BackuptoTgbot(c *gin.Context) { | ||||
| 	a.Tgbot.SendBackupToAdmins() | ||||
| } | ||||
|  |  | |||
|  | @ -24,9 +24,12 @@ func NewInboundController(g *gin.RouterGroup) *InboundController { | |||
| } | ||||
| 
 | ||||
| func (a *InboundController) initRouter(g *gin.RouterGroup) { | ||||
| 	g = g.Group("/inbound") | ||||
| 
 | ||||
| 	g.POST("/list", a.getInbounds) | ||||
| 	g.GET("/list", a.getInbounds) | ||||
| 	g.GET("/get/:id", a.getInbound) | ||||
| 	g.GET("/getClientTraffics/:email", a.getClientTraffics) | ||||
| 	g.GET("/getClientTrafficsById/:id", a.getClientTrafficsById) | ||||
| 
 | ||||
| 	g.POST("/add", a.addInbound) | ||||
| 	g.POST("/del/:id", a.delInbound) | ||||
| 	g.POST("/update/:id", a.updateInbound) | ||||
|  | @ -41,6 +44,8 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) { | |||
| 	g.POST("/delDepletedClients/:id", a.delDepletedClients) | ||||
| 	g.POST("/import", a.importInbound) | ||||
| 	g.POST("/onlines", a.onlines) | ||||
| 	g.POST("/lastOnline", a.lastOnline) | ||||
| 	g.POST("/updateClientTraffic/:email", a.updateClientTraffic) | ||||
| } | ||||
| 
 | ||||
| func (a *InboundController) getInbounds(c *gin.Context) { | ||||
|  |  | |||
|  | @ -37,11 +37,17 @@ func NewServerController(g *gin.RouterGroup) *ServerController { | |||
| } | ||||
| 
 | ||||
| func (a *ServerController) initRouter(g *gin.RouterGroup) { | ||||
| 	g = g.Group("/server") | ||||
| 
 | ||||
| 	g.Use(a.checkLogin) | ||||
| 	g.POST("/status", a.status) | ||||
| 	g.POST("/getXrayVersion", a.getXrayVersion) | ||||
| 	g.GET("/status", a.status) | ||||
| 	g.GET("/getXrayVersion", a.getXrayVersion) | ||||
| 	g.GET("/getConfigJson", a.getConfigJson) | ||||
| 	g.GET("/getDb", a.getDb) | ||||
| 	g.GET("/getNewUUID", a.getNewUUID) | ||||
| 	g.GET("/getNewX25519Cert", a.getNewX25519Cert) | ||||
| 	g.GET("/getNewmldsa65", a.getNewmldsa65) | ||||
| 	g.GET("/getNewmlkem768", a.getNewmlkem768) | ||||
| 	g.GET("/getNewVlessEnc", a.getNewVlessEnc) | ||||
| 
 | ||||
| 	g.POST("/stopXrayService", a.stopXrayService) | ||||
| 	g.POST("/restartXrayService", a.restartXrayService) | ||||
| 	g.POST("/installXray/:version", a.installXray) | ||||
|  | @ -49,13 +55,8 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) { | |||
| 	g.POST("/updateGeofile/:fileName", a.updateGeofile) | ||||
| 	g.POST("/logs/:count", a.getLogs) | ||||
| 	g.POST("/xraylogs/:count", a.getXrayLogs) | ||||
| 	g.POST("/getConfigJson", a.getConfigJson) | ||||
| 	g.GET("/getDb", a.getDb) | ||||
| 	g.POST("/importDB", a.importDB) | ||||
| 	g.POST("/getNewX25519Cert", a.getNewX25519Cert) | ||||
| 	g.POST("/getNewmldsa65", a.getNewmldsa65) | ||||
| 	g.POST("/getNewEchCert", a.getNewEchCert) | ||||
| 	g.POST("/getNewVlessEnc", a.getNewVlessEnc) | ||||
| } | ||||
| 
 | ||||
| func (a *ServerController) refreshStatus() { | ||||
|  | @ -276,3 +277,22 @@ func (a *ServerController) getNewVlessEnc(c *gin.Context) { | |||
| 	} | ||||
| 	jsonObj(c, out, nil) | ||||
| } | ||||
| 
 | ||||
| func (a *ServerController) getNewUUID(c *gin.Context) { | ||||
| 	uuidResp, err := a.serverService.GetNewUUID() | ||||
| 	if err != nil { | ||||
| 		jsonMsg(c, "Failed to generate UUID", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	jsonObj(c, uuidResp, nil) | ||||
| } | ||||
| 
 | ||||
| func (a *ServerController) getNewmlkem768(c *gin.Context) { | ||||
| 	out, err := a.serverService.GetNewmlkem768() | ||||
| 	if err != nil { | ||||
| 		jsonMsg(c, "Failed to generate mlkem768 keys", err) | ||||
| 		return | ||||
| 	} | ||||
| 	jsonObj(c, out, nil) | ||||
| } | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ type XUIController struct { | |||
| 	BaseController | ||||
| 
 | ||||
| 	inboundController     *InboundController | ||||
| 	serverController      *ServerController | ||||
| 	settingController     *SettingController | ||||
| 	xraySettingController *XraySettingController | ||||
| } | ||||
|  | @ -28,6 +29,7 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) { | |||
| 	g.GET("/xray", a.xraySettings) | ||||
| 
 | ||||
| 	a.inboundController = NewInboundController(g) | ||||
| 	a.serverController = NewServerController(g) | ||||
| 	a.settingController = NewSettingController(g) | ||||
| 	a.xraySettingController = NewXraySettingController(g) | ||||
| } | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ | |||
|       <a-input v-model.trim="inbound.settings.decryption"></a-input> | ||||
|     </a-form-item> | ||||
|     <a-form-item label="encryption"> | ||||
|       <a-input v-model="inbound.settings.encryption" disabled></a-input> | ||||
|       <a-input v-model="inbound.settings.encryption"></a-input> | ||||
|     </a-form-item> | ||||
|     <a-form-item label=" "> | ||||
|       <a-space> | ||||
|  |  | |||
|  | @ -830,7 +830,7 @@ | |||
|             }, | ||||
|             async getDBInbounds() { | ||||
|                 this.refreshing = true; | ||||
|                 const msg = await HttpUtil.post('/panel/inbound/list'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/inbounds/list'); | ||||
|                 if (!msg.success) { | ||||
|                     this.refreshing = false; | ||||
|                     return; | ||||
|  | @ -845,7 +845,7 @@ | |||
|                 }, 500); | ||||
|             }, | ||||
|             async getOnlineUsers() { | ||||
|                 const msg = await HttpUtil.post('/panel/inbound/onlines'); | ||||
|                 const msg = await HttpUtil.post('/panel/api/inbounds/onlines'); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|                 } | ||||
|  | @ -1099,7 +1099,7 @@ | |||
|                     streamSettings: baseInbound.stream.toString(), | ||||
|                     sniffing: baseInbound.sniffing.toString(), | ||||
|                 }; | ||||
|                 await this.submit('/panel/inbound/add', data, inModal); | ||||
|                 await this.submit('/panel/api/inbounds/add', data, inModal); | ||||
|             }, | ||||
|             openAddInbound() { | ||||
|                 inModal.show({ | ||||
|  | @ -1148,7 +1148,7 @@ | |||
|                 } | ||||
|                 data.sniffing = inbound.sniffing.toString(); | ||||
| 
 | ||||
|                 await this.submit('/panel/inbound/add', data, inModal); | ||||
|                 await this.submit('/panel/api/inbounds/add', data, inModal); | ||||
|             }, | ||||
|             async updateInbound(inbound, dbInbound) { | ||||
|                 const data = { | ||||
|  | @ -1171,7 +1171,7 @@ | |||
|                 } | ||||
|                 data.sniffing = inbound.sniffing.toString(); | ||||
| 
 | ||||
|                 await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal); | ||||
|                 await this.submit(`/panel/api/inbounds/update/${dbInbound.id}`, data, inModal); | ||||
|             }, | ||||
|             openAddClient(dbInboundId) { | ||||
|                 dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); | ||||
|  | @ -1226,14 +1226,14 @@ | |||
|                     id: dbInboundId, | ||||
|                     settings: '{"clients": [' + clients.toString() + ']}', | ||||
|                 }; | ||||
|                 await this.submit(`/panel/inbound/addClient`, data, modal); | ||||
|                 await this.submit(`/panel/api/inbounds/addClient`, data, modal); | ||||
|             }, | ||||
|             async updateClient(client, dbInboundId, clientId) { | ||||
|                 const data = { | ||||
|                     id: dbInboundId, | ||||
|                     settings: '{"clients": [' + client.toString() + ']}', | ||||
|                 }; | ||||
|                 await this.submit(`/panel/inbound/updateClient/${clientId}`, data, clientModal); | ||||
|                 await this.submit(`/panel/api/inbounds/updateClient/${clientId}`, data, clientModal); | ||||
|             }, | ||||
|             resetTraffic(dbInboundId) { | ||||
|                 dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); | ||||
|  | @ -1258,7 +1258,7 @@ | |||
|                     class: themeSwitcher.currentTheme, | ||||
|                     okText: '{{ i18n "delete"}}', | ||||
|                     cancelText: '{{ i18n "cancel"}}', | ||||
|                     onOk: () => this.submit('/panel/inbound/del/' + dbInboundId), | ||||
|                     onOk: () => this.submit('/panel/api/inbounds/del/' + dbInboundId), | ||||
|                 }); | ||||
|             }, | ||||
|             delClient(dbInboundId, client,confirmation = true) { | ||||
|  | @ -1271,10 +1271,10 @@ | |||
|                         class: themeSwitcher.currentTheme, | ||||
|                         okText: '{{ i18n "delete"}}', | ||||
|                         cancelText: '{{ i18n "cancel"}}', | ||||
|                         onOk: () => this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`), | ||||
|                         onOk: () => this.submit(`/panel/api/inbounds/${dbInboundId}/delClient/${clientId}`), | ||||
|                     }); | ||||
|                 } else { | ||||
|                     this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`); | ||||
|                     this.submit(`/panel/api/inbounds/${dbInboundId}/delClient/${clientId}`); | ||||
|                 } | ||||
|             }, | ||||
|             getSubGroupClients(dbInbounds, currentClient) { | ||||
|  | @ -1353,7 +1353,7 @@ | |||
|             switchEnable(dbInboundId,state) { | ||||
|               dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); | ||||
|               dbInbound.enable = state; | ||||
|               this.submit(`/panel/inbound/update/${dbInboundId}`, dbInbound); | ||||
|               this.submit(`/panel/api/inbounds/update/${dbInboundId}`, dbInbound); | ||||
|             }, | ||||
|             async switchEnableClient(dbInboundId, client) { | ||||
|                 this.loading() | ||||
|  | @ -1383,10 +1383,10 @@ | |||
|                         class: themeSwitcher.currentTheme, | ||||
|                         okText: '{{ i18n "reset"}}', | ||||
|                         cancelText: '{{ i18n "cancel"}}', | ||||
|                         onOk: () => this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email), | ||||
|                         onOk: () => this.submit('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + client.email), | ||||
|                     }) | ||||
|                 } else { | ||||
|                     this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email); | ||||
|                     this.submit('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + client.email); | ||||
|                 } | ||||
|             }, | ||||
|             resetAllTraffic() { | ||||
|  | @ -1396,7 +1396,7 @@ | |||
|                     class: themeSwitcher.currentTheme, | ||||
|                     okText: '{{ i18n "reset"}}', | ||||
|                     cancelText: '{{ i18n "cancel"}}', | ||||
|                     onOk: () => this.submit('/panel/inbound/resetAllTraffics'), | ||||
|                     onOk: () => this.submit('/panel/api/inbounds/resetAllTraffics'), | ||||
|                 }); | ||||
|             }, | ||||
|             resetAllClientTraffics(dbInboundId) { | ||||
|  | @ -1406,7 +1406,7 @@ | |||
|                     class: themeSwitcher.currentTheme, | ||||
|                     okText: '{{ i18n "reset"}}', | ||||
|                     cancelText: '{{ i18n "cancel"}}', | ||||
|                     onOk: () => this.submit('/panel/inbound/resetAllClientTraffics/' + dbInboundId), | ||||
|                     onOk: () => this.submit('/panel/api/inbounds/resetAllClientTraffics/' + dbInboundId), | ||||
|                 }) | ||||
|             }, | ||||
|             delDepletedClients(dbInboundId) { | ||||
|  | @ -1416,7 +1416,7 @@ | |||
|                     class: themeSwitcher.currentTheme, | ||||
|                     okText: '{{ i18n "delete"}}', | ||||
|                     cancelText: '{{ i18n "cancel"}}', | ||||
|                     onOk: () => this.submit('/panel/inbound/delDepletedClients/' + dbInboundId), | ||||
|                     onOk: () => this.submit('/panel/api/inbounds/delDepletedClients/' + dbInboundId), | ||||
|                 }) | ||||
|             }, | ||||
|             isExpiry(dbInbound, index) { | ||||
|  | @ -1542,7 +1542,7 @@ | |||
|                     value: '', | ||||
|                     okText: '{{ i18n "pages.inbounds.import" }}', | ||||
|                     confirm: async (dbInboundText) => { | ||||
|                         await this.submit('/panel/inbound/import', {data: dbInboundText}, promptModal); | ||||
|                         await this.submit('/panel/api/inbounds/import', {data: dbInboundText}, promptModal); | ||||
|                     }, | ||||
|                 }); | ||||
|             }, | ||||
|  |  | |||
|  | @ -746,7 +746,7 @@ ${dateTime} | |||
|             }, | ||||
|             async getStatus() { | ||||
|                 try { | ||||
|                     const msg = await HttpUtil.post('/server/status'); | ||||
|                     const msg = await HttpUtil.get('/panel/api/server/status'); | ||||
|                     if (msg.success) { | ||||
|                         if (!this.loadingStates.fetched) { | ||||
|                             this.loadingStates.fetched = true; | ||||
|  | @ -763,7 +763,7 @@ ${dateTime} | |||
|             }, | ||||
|             async openSelectV2rayVersion() { | ||||
|                 this.loading(true); | ||||
|                 const msg = await HttpUtil.post('server/getXrayVersion'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/server/getXrayVersion'); | ||||
|                 this.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -780,7 +780,7 @@ ${dateTime} | |||
|                     onOk: async () => { | ||||
|                         versionModal.hide(); | ||||
|                         this.loading(true, '{{ i18n "pages.index.dontRefresh"}}'); | ||||
|                         await HttpUtil.post(`/server/installXray/${version}`); | ||||
|                         await HttpUtil.post(`/panel/api/server/installXray/${version}`); | ||||
|                         this.loading(false); | ||||
|                     }, | ||||
|                 }); | ||||
|  | @ -798,9 +798,9 @@ ${dateTime} | |||
|                     onOk: async () => { | ||||
|                         versionModal.hide(); | ||||
|                         this.loading(true, '{{ i18n "pages.index.dontRefresh"}}'); | ||||
|                         const url = isSingleFile  | ||||
|                             ? `/server/updateGeofile/${fileName}`  | ||||
|                             : `/server/updateGeofile`; | ||||
|                         const url = isSingleFile | ||||
|                             ? `/panel/api/server/updateGeofile/${fileName}` | ||||
|                             : `/panel/api/server/updateGeofile`; | ||||
|                         await HttpUtil.post(url); | ||||
|                         this.loading(false); | ||||
|                     }, | ||||
|  | @ -808,7 +808,7 @@ ${dateTime} | |||
|             }, | ||||
|             async stopXrayService() { | ||||
|                 this.loading(true); | ||||
|                 const msg = await HttpUtil.post('server/stopXrayService'); | ||||
|                 const msg = await HttpUtil.post('/panel/api/server/stopXrayService'); | ||||
|                 this.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -816,7 +816,7 @@ ${dateTime} | |||
|             }, | ||||
|             async restartXrayService() { | ||||
|                 this.loading(true); | ||||
|                 const msg = await HttpUtil.post('server/restartXrayService'); | ||||
|                 const msg = await HttpUtil.post('/panel/api/server/restartXrayService'); | ||||
|                 this.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -824,7 +824,7 @@ ${dateTime} | |||
|             }, | ||||
|             async openLogs(){ | ||||
|                 logModal.loading = true; | ||||
|                 const msg = await HttpUtil.post('server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog}); | ||||
|                 const msg = await HttpUtil.post('/panel/api/server/logs/'+logModal.rows,{level: logModal.level, syslog: logModal.syslog}); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|                 } | ||||
|  | @ -834,7 +834,7 @@ ${dateTime} | |||
|             }, | ||||
|             async openXrayLogs(){ | ||||
|               xraylogModal.loading = true; | ||||
|                 const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows,{filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy}); | ||||
|                 const msg = await HttpUtil.post('/panel/api/server/xraylogs/'+xraylogModal.rows,{filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy}); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|                 } | ||||
|  | @ -844,7 +844,7 @@ ${dateTime} | |||
|             }, | ||||
|             async openConfig() { | ||||
|                 this.loading(true); | ||||
|                 const msg = await HttpUtil.post('server/getConfigJson'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/server/getConfigJson'); | ||||
|                 this.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -855,7 +855,7 @@ ${dateTime} | |||
|               backupModal.show(); | ||||
|             }, | ||||
|             exportDatabase() { | ||||
|                 window.location = basePath + 'server/getDb'; | ||||
|                 window.location = basePath + 'panel/api/server/getDb'; | ||||
|             }, | ||||
|             importDatabase() { | ||||
|                 const fileInput = document.createElement('input'); | ||||
|  | @ -868,7 +868,7 @@ ${dateTime} | |||
|                         formData.append('db', dbFile); | ||||
|                         backupModal.hide(); | ||||
|                         this.loading(true); | ||||
|                         const uploadMsg = await HttpUtil.post('server/importDB', formData, { | ||||
|                         const uploadMsg = await HttpUtil.post('/panel/api/server/importDB', formData, { | ||||
|                             headers: { | ||||
|                                 'Content-Type': 'multipart/form-data', | ||||
|                             } | ||||
|  |  | |||
|  | @ -121,7 +121,7 @@ | |||
|         }, | ||||
|         methods: { | ||||
|             async getDBClientIps(email) { | ||||
|                 const msg = await HttpUtil.post(`/panel/inbound/clientIps/${email}`); | ||||
|                 const msg = await HttpUtil.post(`/panel/api/inbounds/clientIps/${email}`); | ||||
|                 if (!msg.success) { | ||||
|                     document.getElementById("clientIPs").value = msg.obj; | ||||
|                     return; | ||||
|  | @ -139,7 +139,7 @@ | |||
|             }, | ||||
|             async clearDBClientIps(email) { | ||||
|                 try { | ||||
|                     const msg = await HttpUtil.post(`/panel/inbound/clearClientIps/${email}`); | ||||
|                     const msg = await HttpUtil.post(`/panel/api/inbounds/clearClientIps/${email}`); | ||||
|                     if (!msg.success) { | ||||
|                         return; | ||||
|                     } | ||||
|  | @ -156,7 +156,7 @@ | |||
|                     cancelText: '{{ i18n "cancel"}}', | ||||
|                     onOk: async () => { | ||||
|                         iconElement.disabled = true; | ||||
|                         const msg = await HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + email); | ||||
|                         const msg = await HttpUtil.postWithModal('/panel/api/inbounds/' + dbInboundId + '/resetClientTraffic/' + email); | ||||
|                         if (msg.success) { | ||||
|                             this.clientModal.clientStats.up = 0; | ||||
|                             this.clientModal.clientStats.down = 0; | ||||
|  |  | |||
|  | @ -492,7 +492,7 @@ | |||
| </a-modal> | ||||
| <script> | ||||
|   function refreshIPs(email) { | ||||
|     return HttpUtil.post(`/panel/inbound/clientIps/${email}`).then((msg) => { | ||||
|     return HttpUtil.post(`/panel/api/inbounds/clientIps/${email}`).then((msg) => { | ||||
|       if (msg.success) { | ||||
|         try { | ||||
|           return JSON.parse(msg.obj).join(', '); | ||||
|  | @ -613,7 +613,7 @@ | |||
|           }); | ||||
|       }, | ||||
|       clearClientIps() { | ||||
|         HttpUtil.post(`/panel/inbound/clearClientIps/${this.infoModal.clientStats.email}`) | ||||
|         HttpUtil.post(`/panel/api/inbounds/clearClientIps/${this.infoModal.clientStats.email}`) | ||||
|           .then((msg) => { | ||||
|             if (!msg.success) { | ||||
|               return; | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ | |||
|             }, | ||||
|             async getNewX25519Cert() { | ||||
|                 inModal.loading(true); | ||||
|                 const msg = await HttpUtil.post('/server/getNewX25519Cert'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/server/getNewX25519Cert'); | ||||
|                 inModal.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -146,7 +146,7 @@ | |||
|             }, | ||||
|             async getNewmldsa65() { | ||||
|                 inModal.loading(true); | ||||
|                 const msg = await HttpUtil.post('/server/getNewmldsa65'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/server/getNewmldsa65'); | ||||
|                 inModal.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -160,7 +160,7 @@ | |||
|             }, | ||||
|             async getNewEchCert() { | ||||
|                 inModal.loading(true); | ||||
|                 const msg = await HttpUtil.post('/server/getNewEchCert', { sni: inModal.inbound.stream.tls.sni }); | ||||
|                 const msg = await HttpUtil.post('/panel/api/server/getNewEchCert', { sni: inModal.inbound.stream.tls.sni }); | ||||
|                 inModal.loading(false); | ||||
|                 if (!msg.success) { | ||||
|                     return; | ||||
|  | @ -174,7 +174,7 @@ | |||
|             }, | ||||
|             async getNewVlessEnc() { | ||||
|                 inModal.loading(true); | ||||
|                 const msg = await HttpUtil.post('/server/getNewVlessEnc'); | ||||
|                 const msg = await HttpUtil.get('/panel/api/server/getNewVlessEnc'); | ||||
|                 inModal.loading(false); | ||||
| 
 | ||||
|                 if (!msg.success) { | ||||
|  |  | |||
|  | @ -151,7 +151,7 @@ | |||
|     methods: { | ||||
|       async getStatus() { | ||||
|         try { | ||||
|           const msg = await HttpUtil.post('/server/status'); | ||||
|           const msg = await HttpUtil.get('/panel/api/server/status'); | ||||
|           if (msg.success) { | ||||
|             this.serverStatus = msg.obj; | ||||
|           } | ||||
|  |  | |||
|  | @ -420,7 +420,7 @@ | |||
|       }, | ||||
|       async restartXray() { | ||||
|         this.loading(true); | ||||
|         const msg = await HttpUtil.post("server/restartXrayService"); | ||||
|         const msg = await HttpUtil.post("/panel/api/server/restartXrayService"); | ||||
|         this.loading(false); | ||||
|         if (msg.success) { | ||||
|           await PromiseUtil.sleep(500); | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ import ( | |||
| 	"x-ui/util/sys" | ||||
| 	"x-ui/xray" | ||||
| 
 | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/shirou/gopsutil/v4/cpu" | ||||
| 	"github.com/shirou/gopsutil/v4/disk" | ||||
| 	"github.com/shirou/gopsutil/v4/host" | ||||
|  | @ -872,12 +873,6 @@ func (s *ServerService) GetNewEchCert(sni string) (interface{}, error) { | |||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| type AuthBlock struct { | ||||
| 	Label      string `json:"label"` | ||||
| 	Decryption string `json:"decryption"` | ||||
| 	Encryption string `json:"encryption"` | ||||
| } | ||||
| 
 | ||||
| func (s *ServerService) GetNewVlessEnc() (any, error) { | ||||
| 	cmd := exec.Command(xray.GetBinaryPath(), "vlessenc") | ||||
| 	var out bytes.Buffer | ||||
|  | @ -887,37 +882,70 @@ func (s *ServerService) GetNewVlessEnc() (any, error) { | |||
| 	} | ||||
| 
 | ||||
| 	lines := strings.Split(out.String(), "\n") | ||||
| 
 | ||||
| 	var blocks []AuthBlock | ||||
| 	var current *AuthBlock | ||||
| 	var auths []map[string]string | ||||
| 	var current map[string]string | ||||
| 
 | ||||
| 	for _, line := range lines { | ||||
| 		line = strings.TrimSpace(line) | ||||
| 		if strings.HasPrefix(line, "Authentication:") { | ||||
| 			if current != nil { | ||||
| 				blocks = append(blocks, *current) | ||||
| 				auths = append(auths, current) | ||||
| 			} | ||||
| 			current = map[string]string{ | ||||
| 				"label": strings.TrimSpace(strings.TrimPrefix(line, "Authentication:")), | ||||
| 			} | ||||
| 			current = &AuthBlock{Label: strings.TrimSpace(strings.TrimPrefix(line, "Authentication:"))} | ||||
| 		} else if strings.HasPrefix(line, `"decryption"`) || strings.HasPrefix(line, `"encryption"`) { | ||||
| 			parts := strings.SplitN(line, ":", 2) | ||||
| 			if len(parts) == 2 && current != nil { | ||||
| 				key := strings.Trim(parts[0], `" `) | ||||
| 				val := strings.Trim(parts[1], `" `) | ||||
| 				switch key { | ||||
| 				case "decryption": | ||||
| 					current.Decryption = val | ||||
| 				case "encryption": | ||||
| 					current.Encryption = val | ||||
| 				} | ||||
| 				current[key] = val | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if current != nil { | ||||
| 		blocks = append(blocks, *current) | ||||
| 		auths = append(auths, current) | ||||
| 	} | ||||
| 
 | ||||
| 	return map[string]any{ | ||||
| 		"auths": blocks, | ||||
| 		"auths": auths, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (s *ServerService) GetNewUUID() (map[string]string, error) { | ||||
| 	newUUID, err := uuid.NewRandom() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to generate UUID: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return map[string]string{ | ||||
| 		"uuid": newUUID.String(), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (s *ServerService) GetNewmlkem768() (any, error) { | ||||
| 	// Run the command
 | ||||
| 	cmd := exec.Command(xray.GetBinaryPath(), "mlkem768") | ||||
| 	var out bytes.Buffer | ||||
| 	cmd.Stdout = &out | ||||
| 	err := cmd.Run() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	lines := strings.Split(out.String(), "\n") | ||||
| 
 | ||||
| 	SeedLine := strings.Split(lines[0], ":") | ||||
| 	ClientLine := strings.Split(lines[1], ":") | ||||
| 
 | ||||
| 	seed := strings.TrimSpace(SeedLine[1]) | ||||
| 	client := strings.TrimSpace(ClientLine[1]) | ||||
| 
 | ||||
| 	keyPair := map[string]any{ | ||||
| 		"seed":   seed, | ||||
| 		"client": client, | ||||
| 	} | ||||
| 
 | ||||
| 	return keyPair, nil | ||||
| } | ||||
|  |  | |||
|  | @ -176,7 +176,7 @@ func (s *Server) initRouter() (*gin.Engine, error) { | |||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	engine.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{basePath + "panel/API/"}))) | ||||
| 	engine.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{basePath + "panel/api/"}))) | ||||
| 	assetsBasePath := basePath + "assets/" | ||||
| 
 | ||||
| 	store := cookie.NewStore(secret) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Sanaei
						Sanaei