1
0

client_inbound_apply.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "strings"
  7. "time"
  8. "github.com/mhsanaei/3x-ui/v3/internal/database"
  9. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  10. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  11. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  12. "github.com/mhsanaei/3x-ui/v3/internal/util/random"
  13. "github.com/mhsanaei/3x-ui/v3/internal/xray"
  14. )
  15. // delInboundClients removes several clients from a single inbound in one pass:
  16. // one settings rewrite, one runtime sweep, one Save and one SyncInbound for the
  17. // whole batch, instead of repeating the full per-client cycle. It mirrors the
  18. // semantics of DelInboundClientByEmail for each removed client. needRestart is
  19. // the OR across all removals.
  20. func (s *ClientService) delInboundClients(inboundSvc *InboundService, inboundId int, recs []*model.ClientRecord, keepTraffic bool) (bool, error) {
  21. if len(recs) == 0 {
  22. return false, nil
  23. }
  24. defer lockInbound(inboundId).Unlock()
  25. oldInbound, err := inboundSvc.GetInbound(inboundId)
  26. if err != nil {
  27. logger.Error("Load Old Data Error")
  28. return false, err
  29. }
  30. var settings map[string]any
  31. if err := json.Unmarshal([]byte(oldInbound.Settings), &settings); err != nil {
  32. return false, err
  33. }
  34. // Match by email — the client's stable identity (see Delete). Removes every
  35. // entry carrying a wanted email, independent of credential drift.
  36. wanted := make(map[string]struct{}, len(recs))
  37. for _, rec := range recs {
  38. if rec.Email != "" {
  39. wanted[rec.Email] = struct{}{}
  40. }
  41. }
  42. interfaceClients, ok := settings["clients"].([]any)
  43. if !ok {
  44. return false, common.NewError("invalid clients format in inbound settings")
  45. }
  46. type removedClient struct {
  47. email string
  48. needApiDel bool
  49. }
  50. removed := make([]removedClient, 0, len(wanted))
  51. newClients := make([]any, 0, len(interfaceClients))
  52. for _, client := range interfaceClients {
  53. c, ok := client.(map[string]any)
  54. if !ok {
  55. newClients = append(newClients, client)
  56. continue
  57. }
  58. email, _ := c["email"].(string)
  59. if _, hit := wanted[email]; hit && email != "" {
  60. enable, _ := c["enable"].(bool)
  61. removed = append(removed, removedClient{email: email, needApiDel: enable})
  62. continue
  63. }
  64. newClients = append(newClients, client)
  65. }
  66. if len(removed) == 0 {
  67. return false, nil
  68. }
  69. db := database.GetDB()
  70. newClients = compactOrphans(db, newClients)
  71. if newClients == nil {
  72. newClients = []any{}
  73. }
  74. settings["clients"] = newClients
  75. newSettings, err := json.MarshalIndent(settings, "", " ")
  76. if err != nil {
  77. return false, err
  78. }
  79. oldInbound.Settings = string(newSettings)
  80. var sharedSet map[string]bool
  81. if !keepTraffic {
  82. removedEmails := make([]string, 0, len(removed))
  83. for _, r := range removed {
  84. if r.email != "" {
  85. removedEmails = append(removedEmails, r.email)
  86. }
  87. }
  88. var sharedErr error
  89. sharedSet, sharedErr = inboundSvc.emailsUsedByOtherInbounds(removedEmails, inboundId)
  90. if sharedErr != nil {
  91. return false, sharedErr
  92. }
  93. }
  94. needRestart := false
  95. markDirty := false
  96. for _, r := range removed {
  97. email := r.email
  98. emailShared := sharedSet[strings.ToLower(strings.TrimSpace(email))]
  99. if !emailShared && !keepTraffic {
  100. if err := inboundSvc.DelClientIPs(db, email); err != nil {
  101. logger.Error("Error in delete client IPs")
  102. return needRestart, err
  103. }
  104. }
  105. if len(email) > 0 {
  106. var enables []bool
  107. if err := db.Model(xray.ClientTraffic{}).Where("email = ?", email).Limit(1).Pluck("enable", &enables).Error; err != nil {
  108. logger.Error("Get stats error")
  109. return needRestart, err
  110. }
  111. notDepleted := len(enables) > 0 && enables[0]
  112. if !emailShared && !keepTraffic {
  113. if err := inboundSvc.DelClientStat(db, email); err != nil {
  114. logger.Error("Delete stats Data Error")
  115. return needRestart, err
  116. }
  117. }
  118. if r.needApiDel && notDepleted && oldInbound.NodeID == nil {
  119. rt, rterr := inboundSvc.runtimeFor(oldInbound)
  120. if rterr != nil {
  121. needRestart = true
  122. } else if err1 := rt.RemoveUser(context.Background(), oldInbound, email); err1 != nil {
  123. if !strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", email)) {
  124. needRestart = true
  125. }
  126. }
  127. }
  128. }
  129. if oldInbound.NodeID != nil && len(email) > 0 {
  130. rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
  131. if perr != nil {
  132. return needRestart, perr
  133. }
  134. if dirty {
  135. markDirty = true
  136. }
  137. if push {
  138. if err1 := rt.DeleteUser(context.Background(), oldInbound, email); err1 != nil {
  139. logger.Warning("Error in deleting client on", rt.Name(), ":", err1)
  140. markDirty = true
  141. }
  142. }
  143. }
  144. }
  145. if err := db.Save(oldInbound).Error; err != nil {
  146. return needRestart, err
  147. }
  148. finalClients, gcErr := inboundSvc.GetClients(oldInbound)
  149. if gcErr != nil {
  150. return needRestart, gcErr
  151. }
  152. if err := s.SyncInbound(db, inboundId, finalClients); err != nil {
  153. return needRestart, err
  154. }
  155. if markDirty && oldInbound.NodeID != nil {
  156. if dErr := (&NodeService{}).MarkNodeDirty(*oldInbound.NodeID); dErr != nil {
  157. logger.Warning("mark node dirty failed:", dErr)
  158. }
  159. }
  160. return needRestart, nil
  161. }
  162. func (s *ClientService) checkEmailsExistForClients(inboundSvc *InboundService, clients []model.Client, emailSubIDs map[string]string) (string, error) {
  163. if emailSubIDs == nil {
  164. var err error
  165. emailSubIDs, err = inboundSvc.getAllEmailSubIDs()
  166. if err != nil {
  167. return "", err
  168. }
  169. }
  170. seen := make(map[string]string, len(clients))
  171. for _, client := range clients {
  172. if client.Email == "" {
  173. continue
  174. }
  175. key := strings.ToLower(client.Email)
  176. if prev, ok := seen[key]; ok {
  177. if prev != client.SubID || client.SubID == "" {
  178. return client.Email, nil
  179. }
  180. continue
  181. }
  182. seen[key] = client.SubID
  183. if existingSub, ok := emailSubIDs[key]; ok {
  184. if client.SubID == "" || existingSub == "" || existingSub != client.SubID {
  185. return client.Email, nil
  186. }
  187. }
  188. }
  189. return "", nil
  190. }
  191. func (s *ClientService) AddInboundClient(inboundSvc *InboundService, data *model.Inbound) (bool, error) {
  192. return s.addInboundClient(inboundSvc, data, nil)
  193. }
  194. // addInboundClient is AddInboundClient with an optional precomputed email→subId
  195. // map. Bulk callers pass a single snapshot so the global getAllEmailSubIDs scan
  196. // runs once for the whole batch instead of once per target inbound; a nil map
  197. // makes it compute its own (the single-add path).
  198. func (s *ClientService) addInboundClient(inboundSvc *InboundService, data *model.Inbound, emailSubIDs map[string]string) (bool, error) {
  199. defer lockInbound(data.Id).Unlock()
  200. clients, err := inboundSvc.GetClients(data)
  201. if err != nil {
  202. return false, err
  203. }
  204. var settings map[string]any
  205. err = json.Unmarshal([]byte(data.Settings), &settings)
  206. if err != nil {
  207. return false, err
  208. }
  209. interfaceClients := settings["clients"].([]any)
  210. nowTs := time.Now().Unix() * 1000
  211. for i := range interfaceClients {
  212. if cm, ok := interfaceClients[i].(map[string]any); ok {
  213. if _, ok2 := cm["created_at"]; !ok2 {
  214. cm["created_at"] = nowTs
  215. }
  216. cm["updated_at"] = nowTs
  217. existingSub, _ := cm["subId"].(string)
  218. if strings.TrimSpace(existingSub) == "" {
  219. cm["subId"] = random.NumLower(16)
  220. }
  221. interfaceClients[i] = cm
  222. }
  223. }
  224. existEmail, err := s.checkEmailsExistForClients(inboundSvc, clients, emailSubIDs)
  225. if err != nil {
  226. return false, err
  227. }
  228. if existEmail != "" {
  229. return false, common.NewError("Duplicate email:", existEmail)
  230. }
  231. oldInbound, err := inboundSvc.GetInbound(data.Id)
  232. if err != nil {
  233. return false, err
  234. }
  235. for _, client := range clients {
  236. if strings.TrimSpace(client.Email) == "" {
  237. return false, common.NewError("client email is required")
  238. }
  239. switch oldInbound.Protocol {
  240. case "trojan":
  241. if client.Password == "" {
  242. return false, common.NewError("empty client ID")
  243. }
  244. case "shadowsocks":
  245. if client.Email == "" {
  246. return false, common.NewError("empty client ID")
  247. }
  248. case "hysteria":
  249. if client.Auth == "" {
  250. return false, common.NewError("empty client ID")
  251. }
  252. default:
  253. if client.ID == "" {
  254. return false, common.NewError("empty client ID")
  255. }
  256. }
  257. }
  258. var oldSettings map[string]any
  259. err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
  260. if err != nil {
  261. return false, err
  262. }
  263. if oldInbound.Protocol == model.Shadowsocks {
  264. applyShadowsocksClientMethod(interfaceClients, oldSettings)
  265. }
  266. oldClients := oldSettings["clients"].([]any)
  267. oldClients = compactOrphans(database.GetDB(), oldClients)
  268. oldClients = append(oldClients, interfaceClients...)
  269. oldSettings["clients"] = oldClients
  270. newSettings, err := json.MarshalIndent(oldSettings, "", " ")
  271. if err != nil {
  272. return false, err
  273. }
  274. oldInbound.Settings = string(newSettings)
  275. db := database.GetDB()
  276. tx := db.Begin()
  277. markDirty := false
  278. defer func() {
  279. if err != nil {
  280. tx.Rollback()
  281. return
  282. }
  283. tx.Commit()
  284. if markDirty && oldInbound.NodeID != nil {
  285. if dErr := (&NodeService{}).MarkNodeDirty(*oldInbound.NodeID); dErr != nil {
  286. logger.Warning("mark node dirty failed:", dErr)
  287. }
  288. }
  289. }()
  290. needRestart := false
  291. rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
  292. if perr != nil {
  293. err = perr
  294. return false, err
  295. }
  296. if dirty {
  297. markDirty = true
  298. }
  299. if oldInbound.NodeID == nil {
  300. if !push {
  301. needRestart = true
  302. } else {
  303. for _, client := range clients {
  304. if len(client.Email) == 0 {
  305. needRestart = true
  306. continue
  307. }
  308. inboundSvc.AddClientStat(tx, data.Id, &client)
  309. if !client.Enable {
  310. continue
  311. }
  312. cipher := ""
  313. if oldInbound.Protocol == "shadowsocks" {
  314. cipher = oldSettings["method"].(string)
  315. }
  316. err1 := rt.AddUser(context.Background(), oldInbound, map[string]any{
  317. "email": client.Email,
  318. "id": client.ID,
  319. "auth": client.Auth,
  320. "security": client.Security,
  321. "flow": client.Flow,
  322. "password": client.Password,
  323. "cipher": cipher,
  324. })
  325. if err1 == nil {
  326. logger.Debug("Client added on", rt.Name(), ":", client.Email)
  327. } else {
  328. logger.Debug("Error in adding client on", rt.Name(), ":", err1)
  329. needRestart = true
  330. }
  331. }
  332. }
  333. } else {
  334. for _, client := range clients {
  335. if len(client.Email) > 0 {
  336. inboundSvc.AddClientStat(tx, data.Id, &client)
  337. }
  338. if push {
  339. if err1 := rt.AddClient(context.Background(), oldInbound, client); err1 != nil {
  340. logger.Warning("Error in adding client on", rt.Name(), ":", err1)
  341. markDirty = true
  342. push = false
  343. }
  344. }
  345. }
  346. }
  347. if err = tx.Save(oldInbound).Error; err != nil {
  348. return false, err
  349. }
  350. finalClients, gcErr := inboundSvc.GetClients(oldInbound)
  351. if gcErr != nil {
  352. err = gcErr
  353. return false, err
  354. }
  355. if err = s.SyncInbound(tx, oldInbound.Id, finalClients); err != nil {
  356. return false, err
  357. }
  358. return needRestart, nil
  359. }
  360. func (s *ClientService) UpdateInboundClient(inboundSvc *InboundService, data *model.Inbound, oldEmail string) (bool, error) {
  361. defer lockInbound(data.Id).Unlock()
  362. clients, err := inboundSvc.GetClients(data)
  363. if err != nil {
  364. return false, err
  365. }
  366. var settings map[string]any
  367. err = json.Unmarshal([]byte(data.Settings), &settings)
  368. if err != nil {
  369. return false, err
  370. }
  371. interfaceClients := settings["clients"].([]any)
  372. oldInbound, err := inboundSvc.GetInbound(data.Id)
  373. if err != nil {
  374. return false, err
  375. }
  376. oldClients, err := inboundSvc.GetClients(oldInbound)
  377. if err != nil {
  378. return false, err
  379. }
  380. newClientId := ""
  381. switch oldInbound.Protocol {
  382. case "trojan":
  383. newClientId = clients[0].Password
  384. case "shadowsocks":
  385. newClientId = clients[0].Email
  386. case "hysteria":
  387. newClientId = clients[0].Auth
  388. default:
  389. newClientId = clients[0].ID
  390. }
  391. // Locate the client to replace by email — the client's stable identity.
  392. // Credentials (uuid/password/auth) can drift from the inbound JSON, so they
  393. // are never used for matching.
  394. clientIndex := -1
  395. for index, oldClient := range oldClients {
  396. if strings.EqualFold(oldClient.Email, oldEmail) {
  397. oldEmail = oldClient.Email
  398. clientIndex = index
  399. break
  400. }
  401. }
  402. if newClientId == "" || clientIndex == -1 {
  403. return false, common.NewError("empty client ID")
  404. }
  405. if strings.TrimSpace(clients[0].Email) == "" {
  406. return false, common.NewError("client email is required")
  407. }
  408. if clients[0].Email != oldEmail {
  409. existEmail, err := s.checkEmailsExistForClients(inboundSvc, clients, nil)
  410. if err != nil {
  411. return false, err
  412. }
  413. if existEmail != "" {
  414. return false, common.NewError("Duplicate email:", existEmail)
  415. }
  416. }
  417. var oldSettings map[string]any
  418. err = json.Unmarshal([]byte(oldInbound.Settings), &oldSettings)
  419. if err != nil {
  420. return false, err
  421. }
  422. settingsClients := oldSettings["clients"].([]any)
  423. var preservedCreated any
  424. var preservedSubID string
  425. if clientIndex >= 0 && clientIndex < len(settingsClients) {
  426. if oldMap, ok := settingsClients[clientIndex].(map[string]any); ok {
  427. if v, ok2 := oldMap["created_at"]; ok2 {
  428. preservedCreated = v
  429. }
  430. preservedSubID, _ = oldMap["subId"].(string)
  431. }
  432. }
  433. if len(interfaceClients) > 0 {
  434. if newMap, ok := interfaceClients[0].(map[string]any); ok {
  435. if preservedCreated == nil {
  436. preservedCreated = time.Now().Unix() * 1000
  437. }
  438. newMap["created_at"] = preservedCreated
  439. newMap["updated_at"] = time.Now().Unix() * 1000
  440. newSub, _ := newMap["subId"].(string)
  441. if strings.TrimSpace(newSub) == "" {
  442. if strings.TrimSpace(preservedSubID) != "" {
  443. newMap["subId"] = preservedSubID
  444. } else {
  445. newMap["subId"] = random.NumLower(16)
  446. }
  447. }
  448. interfaceClients[0] = newMap
  449. }
  450. }
  451. if oldInbound.Protocol == model.Shadowsocks {
  452. applyShadowsocksClientMethod(interfaceClients, oldSettings)
  453. }
  454. settingsClients[clientIndex] = interfaceClients[0]
  455. oldSettings["clients"] = settingsClients
  456. if oldInbound.Protocol == model.VLESS {
  457. hasVisionFlow := false
  458. for _, c := range settingsClients {
  459. cm, ok := c.(map[string]any)
  460. if !ok {
  461. continue
  462. }
  463. if flow, _ := cm["flow"].(string); flow == "xtls-rprx-vision" {
  464. hasVisionFlow = true
  465. break
  466. }
  467. }
  468. if !hasVisionFlow {
  469. delete(oldSettings, "testseed")
  470. }
  471. }
  472. newSettings, err := json.MarshalIndent(oldSettings, "", " ")
  473. if err != nil {
  474. return false, err
  475. }
  476. oldInbound.Settings = string(newSettings)
  477. db := database.GetDB()
  478. tx := db.Begin()
  479. markDirty := false
  480. defer func() {
  481. if err != nil {
  482. tx.Rollback()
  483. return
  484. }
  485. tx.Commit()
  486. if markDirty && oldInbound.NodeID != nil {
  487. if dErr := (&NodeService{}).MarkNodeDirty(*oldInbound.NodeID); dErr != nil {
  488. logger.Warning("mark node dirty failed:", dErr)
  489. }
  490. }
  491. }()
  492. if len(clients[0].Email) > 0 {
  493. if len(oldEmail) > 0 {
  494. emailUnchanged := strings.EqualFold(oldEmail, clients[0].Email)
  495. targetExists := int64(0)
  496. if !emailUnchanged {
  497. if err = tx.Model(xray.ClientTraffic{}).Where("email = ?", clients[0].Email).Count(&targetExists).Error; err != nil {
  498. return false, err
  499. }
  500. }
  501. if emailUnchanged || targetExists == 0 {
  502. err = inboundSvc.UpdateClientStat(tx, oldEmail, &clients[0])
  503. if err != nil {
  504. return false, err
  505. }
  506. err = inboundSvc.UpdateClientIPs(tx, oldEmail, clients[0].Email)
  507. if err != nil {
  508. return false, err
  509. }
  510. } else {
  511. stillUsed, sErr := inboundSvc.emailUsedByOtherInbounds(oldEmail, data.Id)
  512. if sErr != nil {
  513. return false, sErr
  514. }
  515. if !stillUsed {
  516. if err = inboundSvc.DelClientStat(tx, oldEmail); err != nil {
  517. return false, err
  518. }
  519. if err = inboundSvc.DelClientIPs(tx, oldEmail); err != nil {
  520. return false, err
  521. }
  522. }
  523. if err = inboundSvc.UpdateClientStat(tx, clients[0].Email, &clients[0]); err != nil {
  524. return false, err
  525. }
  526. }
  527. } else {
  528. inboundSvc.AddClientStat(tx, data.Id, &clients[0])
  529. }
  530. } else {
  531. stillUsed, err := inboundSvc.emailUsedByOtherInbounds(oldEmail, data.Id)
  532. if err != nil {
  533. return false, err
  534. }
  535. if !stillUsed {
  536. err = inboundSvc.DelClientStat(tx, oldEmail)
  537. if err != nil {
  538. return false, err
  539. }
  540. err = inboundSvc.DelClientIPs(tx, oldEmail)
  541. if err != nil {
  542. return false, err
  543. }
  544. }
  545. }
  546. needRestart := false
  547. if len(oldEmail) > 0 {
  548. rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
  549. if perr != nil {
  550. err = perr
  551. return false, err
  552. }
  553. if dirty {
  554. markDirty = true
  555. }
  556. if oldInbound.NodeID == nil {
  557. if !push {
  558. needRestart = true
  559. } else {
  560. if oldClients[clientIndex].Enable {
  561. err1 := rt.RemoveUser(context.Background(), oldInbound, oldEmail)
  562. if err1 == nil {
  563. logger.Debug("Old client deleted on", rt.Name(), ":", oldEmail)
  564. } else if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", oldEmail)) {
  565. logger.Debug("User is already deleted. Nothing to do more...")
  566. } else {
  567. logger.Debug("Error in deleting client on", rt.Name(), ":", err1)
  568. needRestart = true
  569. }
  570. }
  571. if clients[0].Enable {
  572. cipher := ""
  573. if oldInbound.Protocol == "shadowsocks" {
  574. cipher = oldSettings["method"].(string)
  575. }
  576. err1 := rt.AddUser(context.Background(), oldInbound, map[string]any{
  577. "email": clients[0].Email,
  578. "id": clients[0].ID,
  579. "security": clients[0].Security,
  580. "flow": clients[0].Flow,
  581. "auth": clients[0].Auth,
  582. "password": clients[0].Password,
  583. "cipher": cipher,
  584. })
  585. if err1 == nil {
  586. logger.Debug("Client edited on", rt.Name(), ":", clients[0].Email)
  587. } else {
  588. logger.Debug("Error in adding client on", rt.Name(), ":", err1)
  589. needRestart = true
  590. }
  591. }
  592. }
  593. } else if push {
  594. if err1 := rt.UpdateUser(context.Background(), oldInbound, oldEmail, clients[0]); err1 != nil {
  595. logger.Warning("Error in updating client on", rt.Name(), ":", err1)
  596. markDirty = true
  597. }
  598. }
  599. } else {
  600. logger.Debug("Client old email not found")
  601. needRestart = true
  602. }
  603. if err = tx.Save(oldInbound).Error; err != nil {
  604. return false, err
  605. }
  606. finalClients, gcErr := inboundSvc.GetClients(oldInbound)
  607. if gcErr != nil {
  608. err = gcErr
  609. return false, err
  610. }
  611. if err = s.SyncInbound(tx, oldInbound.Id, finalClients); err != nil {
  612. return false, err
  613. }
  614. return needRestart, nil
  615. }
  616. func (s *ClientService) DelInboundClientByEmail(inboundSvc *InboundService, inboundId int, email string, keepTraffic bool) (bool, error) {
  617. defer lockInbound(inboundId).Unlock()
  618. oldInbound, err := inboundSvc.GetInbound(inboundId)
  619. if err != nil {
  620. logger.Error("Load Old Data Error")
  621. return false, err
  622. }
  623. var settings map[string]any
  624. if err := json.Unmarshal([]byte(oldInbound.Settings), &settings); err != nil {
  625. return false, err
  626. }
  627. interfaceClients, ok := settings["clients"].([]any)
  628. if !ok {
  629. return false, common.NewError("invalid clients format in inbound settings")
  630. }
  631. var newClients []any
  632. needApiDel := false
  633. found := false
  634. for _, client := range interfaceClients {
  635. c, ok := client.(map[string]any)
  636. if !ok {
  637. continue
  638. }
  639. if cEmail, ok := c["email"].(string); ok && cEmail == email {
  640. found = true
  641. needApiDel, _ = c["enable"].(bool)
  642. } else {
  643. newClients = append(newClients, client)
  644. }
  645. }
  646. if !found {
  647. return false, fmt.Errorf("%w for email: %s", ErrClientNotInInbound, email)
  648. }
  649. db := database.GetDB()
  650. newClients = compactOrphans(db, newClients)
  651. if newClients == nil {
  652. newClients = []any{}
  653. }
  654. settings["clients"] = newClients
  655. newSettings, err := json.MarshalIndent(settings, "", " ")
  656. if err != nil {
  657. return false, err
  658. }
  659. oldInbound.Settings = string(newSettings)
  660. emailShared, err := inboundSvc.emailUsedByOtherInbounds(email, inboundId)
  661. if err != nil {
  662. return false, err
  663. }
  664. if !emailShared && !keepTraffic {
  665. if err := inboundSvc.DelClientIPs(db, email); err != nil {
  666. logger.Error("Error in delete client IPs")
  667. return false, err
  668. }
  669. }
  670. needRestart := false
  671. markDirty := false
  672. if len(email) > 0 && !emailShared {
  673. if !keepTraffic {
  674. traffic, err := inboundSvc.GetClientTrafficByEmail(email)
  675. if err != nil {
  676. return false, err
  677. }
  678. if traffic != nil {
  679. if err := inboundSvc.DelClientStat(db, email); err != nil {
  680. logger.Error("Delete stats Data Error")
  681. return false, err
  682. }
  683. }
  684. }
  685. if needApiDel {
  686. rt, push, dirty, perr := inboundSvc.nodePushPlan(oldInbound)
  687. if perr != nil {
  688. return false, perr
  689. }
  690. if dirty {
  691. markDirty = true
  692. }
  693. if oldInbound.NodeID == nil {
  694. if !push {
  695. needRestart = true
  696. } else if err1 := rt.RemoveUser(context.Background(), oldInbound, email); err1 == nil {
  697. logger.Debug("Client deleted on", rt.Name(), ":", email)
  698. needRestart = false
  699. } else if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", email)) {
  700. logger.Debug("User is already deleted. Nothing to do more...")
  701. } else {
  702. logger.Debug("Error in deleting client on", rt.Name(), ":", email)
  703. needRestart = true
  704. }
  705. } else if push {
  706. if err1 := rt.DeleteUser(context.Background(), oldInbound, email); err1 != nil {
  707. logger.Warning("Error in deleting client on", rt.Name(), ":", err1)
  708. markDirty = true
  709. }
  710. }
  711. }
  712. }
  713. if err := db.Save(oldInbound).Error; err != nil {
  714. return false, err
  715. }
  716. finalClients, gcErr := inboundSvc.GetClients(oldInbound)
  717. if gcErr != nil {
  718. return false, gcErr
  719. }
  720. if err := s.SyncInbound(db, inboundId, finalClients); err != nil {
  721. return false, err
  722. }
  723. if markDirty && oldInbound.NodeID != nil {
  724. if dErr := (&NodeService{}).MarkNodeDirty(*oldInbound.NodeID); dErr != nil {
  725. logger.Warning("mark node dirty failed:", dErr)
  726. }
  727. }
  728. return needRestart, nil
  729. }
  730. func (s *ClientService) SetClientTelegramUserID(inboundSvc *InboundService, trafficId int, tgId int64) (bool, error) {
  731. traffic, inbound, err := inboundSvc.GetClientInboundByTrafficID(trafficId)
  732. if err != nil {
  733. return false, err
  734. }
  735. if inbound == nil {
  736. return false, common.NewError("Inbound Not Found For Traffic ID:", trafficId)
  737. }
  738. clientEmail := traffic.Email
  739. oldClients, err := inboundSvc.GetClients(inbound)
  740. if err != nil {
  741. return false, err
  742. }
  743. found := false
  744. for _, oldClient := range oldClients {
  745. if oldClient.Email == clientEmail {
  746. found = true
  747. break
  748. }
  749. }
  750. if !found {
  751. return false, common.NewError("Client Not Found For Email:", clientEmail)
  752. }
  753. var settings map[string]any
  754. err = json.Unmarshal([]byte(inbound.Settings), &settings)
  755. if err != nil {
  756. return false, err
  757. }
  758. clients := settings["clients"].([]any)
  759. var newClients []any
  760. for client_index := range clients {
  761. c := clients[client_index].(map[string]any)
  762. if c["email"] == clientEmail {
  763. c["tgId"] = tgId
  764. c["updated_at"] = time.Now().Unix() * 1000
  765. newClients = append(newClients, any(c))
  766. }
  767. }
  768. settings["clients"] = newClients
  769. modifiedSettings, err := json.MarshalIndent(settings, "", " ")
  770. if err != nil {
  771. return false, err
  772. }
  773. inbound.Settings = string(modifiedSettings)
  774. needRestart, err := s.UpdateInboundClient(inboundSvc, inbound, clientEmail)
  775. return needRestart, err
  776. }
  777. func (s *ClientService) CheckIsEnabledByEmail(inboundSvc *InboundService, clientEmail string) (bool, error) {
  778. _, inbound, err := inboundSvc.GetClientInboundByEmail(clientEmail)
  779. if err != nil {
  780. return false, err
  781. }
  782. if inbound == nil {
  783. return false, common.NewError("Inbound Not Found For Email:", clientEmail)
  784. }
  785. clients, err := inboundSvc.GetClients(inbound)
  786. if err != nil {
  787. return false, err
  788. }
  789. isEnable := false
  790. for _, client := range clients {
  791. if client.Email == clientEmail {
  792. isEnable = client.Enable
  793. break
  794. }
  795. }
  796. return isEnable, err
  797. }
  798. func (s *ClientService) ToggleClientEnableByEmail(inboundSvc *InboundService, clientEmail string) (bool, bool, error) {
  799. _, inbound, err := inboundSvc.GetClientInboundByEmail(clientEmail)
  800. if err != nil {
  801. return false, false, err
  802. }
  803. if inbound == nil {
  804. return false, false, common.NewError("Inbound Not Found For Email:", clientEmail)
  805. }
  806. oldClients, err := inboundSvc.GetClients(inbound)
  807. if err != nil {
  808. return false, false, err
  809. }
  810. found := false
  811. clientOldEnabled := false
  812. for _, oldClient := range oldClients {
  813. if oldClient.Email == clientEmail {
  814. found = true
  815. clientOldEnabled = oldClient.Enable
  816. break
  817. }
  818. }
  819. if !found {
  820. return false, false, common.NewError("Client Not Found For Email:", clientEmail)
  821. }
  822. var settings map[string]any
  823. err = json.Unmarshal([]byte(inbound.Settings), &settings)
  824. if err != nil {
  825. return false, false, err
  826. }
  827. clients := settings["clients"].([]any)
  828. var newClients []any
  829. for client_index := range clients {
  830. c := clients[client_index].(map[string]any)
  831. if c["email"] == clientEmail {
  832. c["enable"] = !clientOldEnabled
  833. c["updated_at"] = time.Now().Unix() * 1000
  834. newClients = append(newClients, any(c))
  835. }
  836. }
  837. settings["clients"] = newClients
  838. modifiedSettings, err := json.MarshalIndent(settings, "", " ")
  839. if err != nil {
  840. return false, false, err
  841. }
  842. inbound.Settings = string(modifiedSettings)
  843. needRestart, err := s.UpdateInboundClient(inboundSvc, inbound, clientEmail)
  844. if err != nil {
  845. return false, needRestart, err
  846. }
  847. return !clientOldEnabled, needRestart, nil
  848. }
  849. func (s *ClientService) SetClientEnableByEmail(inboundSvc *InboundService, clientEmail string, enable bool) (bool, bool, error) {
  850. current, err := s.CheckIsEnabledByEmail(inboundSvc, clientEmail)
  851. if err != nil {
  852. return false, false, err
  853. }
  854. if current == enable {
  855. return false, false, nil
  856. }
  857. newEnabled, needRestart, err := s.ToggleClientEnableByEmail(inboundSvc, clientEmail)
  858. if err != nil {
  859. return false, needRestart, err
  860. }
  861. return newEnabled == enable, needRestart, nil
  862. }
  863. // applyClientFieldByEmail loads the inbound currently hosting clientEmail,
  864. // confirms the client exists, applies mutate to the matching client (plus a
  865. // refreshed updated_at), and hands a single-client update payload to
  866. // UpdateInboundClient. The rebuilt clients array intentionally contains only
  867. // the matched client — that is the input contract UpdateInboundClient expects
  868. // (clients[0] is the new data; clientEmail locates the row to replace). It
  869. // backs the single-field by-email setters below.
  870. func (s *ClientService) applyClientFieldByEmail(inboundSvc *InboundService, clientEmail string, mutate func(c map[string]any)) (bool, error) {
  871. _, inbound, err := inboundSvc.GetClientInboundByEmail(clientEmail)
  872. if err != nil {
  873. return false, err
  874. }
  875. if inbound == nil {
  876. return false, common.NewError("Inbound Not Found For Email:", clientEmail)
  877. }
  878. oldClients, err := inboundSvc.GetClients(inbound)
  879. if err != nil {
  880. return false, err
  881. }
  882. found := false
  883. for _, oldClient := range oldClients {
  884. if oldClient.Email == clientEmail {
  885. found = true
  886. break
  887. }
  888. }
  889. if !found {
  890. return false, common.NewError("Client Not Found For Email:", clientEmail)
  891. }
  892. var settings map[string]any
  893. err = json.Unmarshal([]byte(inbound.Settings), &settings)
  894. if err != nil {
  895. return false, err
  896. }
  897. clients := settings["clients"].([]any)
  898. var newClients []any
  899. for client_index := range clients {
  900. c := clients[client_index].(map[string]any)
  901. if c["email"] == clientEmail {
  902. mutate(c)
  903. c["updated_at"] = time.Now().Unix() * 1000
  904. newClients = append(newClients, any(c))
  905. }
  906. }
  907. settings["clients"] = newClients
  908. modifiedSettings, err := json.MarshalIndent(settings, "", " ")
  909. if err != nil {
  910. return false, err
  911. }
  912. inbound.Settings = string(modifiedSettings)
  913. return s.UpdateInboundClient(inboundSvc, inbound, clientEmail)
  914. }
  915. func (s *ClientService) ResetClientIpLimitByEmail(inboundSvc *InboundService, clientEmail string, count int) (bool, error) {
  916. return s.applyClientFieldByEmail(inboundSvc, clientEmail, func(c map[string]any) {
  917. c["limitIp"] = count
  918. })
  919. }
  920. func (s *ClientService) ResetClientExpiryTimeByEmail(inboundSvc *InboundService, clientEmail string, expiry_time int64) (bool, error) {
  921. return s.applyClientFieldByEmail(inboundSvc, clientEmail, func(c map[string]any) {
  922. c["expiryTime"] = expiry_time
  923. })
  924. }
  925. func (s *ClientService) ResetClientTrafficLimitByEmail(inboundSvc *InboundService, clientEmail string, totalGB int) (bool, error) {
  926. if totalGB < 0 {
  927. return false, common.NewError("totalGB must be >= 0")
  928. }
  929. return s.applyClientFieldByEmail(inboundSvc, clientEmail, func(c map[string]any) {
  930. c["totalGB"] = totalGB * 1024 * 1024 * 1024
  931. })
  932. }