diff --git a/internal/utils/misc.go b/internal/utils/misc.go index b9e733e..80af4bc 100644 --- a/internal/utils/misc.go +++ b/internal/utils/misc.go @@ -22,3 +22,15 @@ func Contains(slice []string, value string) bool { } return false } + +func Mask(text string) string { + res := "" + if len(text) > 12 { + res = text[:8] + "****" + text[len(text)-4:] + } else if len(text) > 8 { + res = text[:4] + "****" + text[len(text)-2:] + } else { + res = "****" + } + return res +} diff --git a/pkg/debrid/providers/alldebrid/alldebrid.go b/pkg/debrid/providers/alldebrid/alldebrid.go index af3ab04..4cd8bb3 100644 --- a/pkg/debrid/providers/alldebrid/alldebrid.go +++ b/pkg/debrid/providers/alldebrid/alldebrid.go @@ -301,7 +301,7 @@ func (ad *AllDebrid) GetFileDownloadLinks(t *types.Torrent) error { for _, file := range t.Files { go func(file types.File) { defer wg.Done() - link, _, err := ad.GetDownloadLink(t, &file) + link, err := ad.GetDownloadLink(t, &file) if err != nil { errCh <- err return @@ -336,7 +336,7 @@ func (ad *AllDebrid) GetFileDownloadLinks(t *types.Torrent) error { links[link.Link] = link } // Update the files with download links - ad.accounts.SetDownloadLinks(nil, links) + ad.accounts.SetDownloadLinks(links) // Check for errors for err := range errCh { @@ -349,7 +349,7 @@ func (ad *AllDebrid) GetFileDownloadLinks(t *types.Torrent) error { return nil } -func (ad *AllDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, *types.Account, error) { +func (ad *AllDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, error) { url := fmt.Sprintf("%s/link/unlock", ad.Host) query := gourl.Values{} query.Add("link", file.Link) @@ -357,21 +357,22 @@ func (ad *AllDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types req, _ := http.NewRequest(http.MethodGet, url, nil) resp, err := ad.client.MakeRequest(req) if err != nil { - return nil, nil, err + return nil, err } var data DownloadLink if err = json.Unmarshal(resp, &data); err != nil { - return nil, nil, err + return nil, err } if data.Error != nil { - return nil, nil, fmt.Errorf("error getting download link: %s", data.Error.Message) + return nil, fmt.Errorf("error getting download link: %s", data.Error.Message) } link := data.Data.Link if link == "" { - return nil, nil, fmt.Errorf("download link is empty") + return nil, fmt.Errorf("download link is empty") } now := time.Now() + account := ad.accounts.Current() return &types.DownloadLink{ Link: file.Link, DownloadLink: link, @@ -380,7 +381,9 @@ func (ad *AllDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types Filename: file.Name, Generated: now, ExpiresAt: now.Add(ad.autoExpiresLinksAfter), - }, nil, nil + Token: account.Token, + MaskedToken: account.MaskedToken, + }, nil } func (ad *AllDebrid) GetTorrents() ([]*types.Torrent, error) { diff --git a/pkg/debrid/providers/debridlink/debrid_link.go b/pkg/debrid/providers/debridlink/debrid_link.go index afebd81..55766f3 100644 --- a/pkg/debrid/providers/debridlink/debrid_link.go +++ b/pkg/debrid/providers/debridlink/debrid_link.go @@ -247,7 +247,7 @@ func (dl *DebridLink) UpdateTorrent(t *types.Torrent) error { t.Files[f.Name] = file } - dl.accounts.SetDownloadLinks(nil, links) + dl.accounts.SetDownloadLinks(links) return nil } @@ -287,6 +287,7 @@ func (dl *DebridLink) SubmitMagnet(t *types.Torrent) (*types.Torrent, error) { links := make(map[string]*types.DownloadLink) now := time.Now() + account := dl.accounts.Current() for _, f := range data.Files { file := types.File{ TorrentId: t.Id, @@ -303,12 +304,14 @@ func (dl *DebridLink) SubmitMagnet(t *types.Torrent) (*types.Torrent, error) { DownloadLink: f.DownloadURL, Generated: now, ExpiresAt: now.Add(dl.autoExpiresLinksAfter), + Token: account.Token, + MaskedToken: account.MaskedToken, } links[file.Link] = link file.DownloadLink = link t.Files[f.Name] = file } - dl.accounts.SetDownloadLinks(nil, links) + dl.accounts.SetDownloadLinks(links) return t, nil } @@ -356,7 +359,7 @@ func (dl *DebridLink) RefreshDownloadLinks() error { return nil } -func (dl *DebridLink) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, *types.Account, error) { +func (dl *DebridLink) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, error) { return dl.accounts.GetDownloadLink(file.Link) } @@ -407,6 +410,7 @@ func (dl *DebridLink) getTorrents(page, perPage int) ([]*types.Torrent, error) { if len(data) == 0 { return torrents, nil } + account := dl.accounts.Current() for _, t := range data { if t.Status != 100 { continue @@ -444,6 +448,8 @@ func (dl *DebridLink) getTorrents(page, perPage int) ([]*types.Torrent, error) { DownloadLink: f.DownloadURL, Generated: now, ExpiresAt: now.Add(dl.autoExpiresLinksAfter), + Token: account.Token, + MaskedToken: account.MaskedToken, } links[file.Link] = link file.DownloadLink = link @@ -451,7 +457,7 @@ func (dl *DebridLink) getTorrents(page, perPage int) ([]*types.Torrent, error) { } torrents = append(torrents, torrent) } - dl.accounts.SetDownloadLinks(nil, links) + dl.accounts.SetDownloadLinks(links) return torrents, nil } diff --git a/pkg/debrid/providers/realdebrid/realdebrid.go b/pkg/debrid/providers/realdebrid/realdebrid.go index 47b88c7..17e1062 100644 --- a/pkg/debrid/providers/realdebrid/realdebrid.go +++ b/pkg/debrid/providers/realdebrid/realdebrid.go @@ -195,7 +195,7 @@ func (r *RealDebrid) handleRarArchive(t *types.Torrent, data torrentInfo, select r.logger.Info().Msgf("RAR file detected, unpacking: %s", t.Name) linkFile := &types.File{TorrentId: t.Id, Link: data.Links[0]} - downloadLinkObj, account, err := r.GetDownloadLink(t, linkFile) + downloadLinkObj, err := r.GetDownloadLink(t, linkFile) if err != nil { r.logger.Debug().Err(err).Msgf("Error getting download link for RAR file: %s. Falling back to single file representation.", t.Name) @@ -244,7 +244,7 @@ func (r *RealDebrid) handleRarArchive(t *types.Torrent, data torrentInfo, select return r.handleRarFallback(t, data) } r.logger.Info().Msgf("Unpacked RAR archive for torrent: %s with %d files", t.Name, len(files)) - r.accounts.SetDownloadLink(account, downloadLinkObj) + r.accounts.SetDownloadLink(downloadLinkObj) return files, nil } @@ -589,7 +589,7 @@ func (r *RealDebrid) GetFileDownloadLinks(t *types.Torrent) error { go func(file types.File) { defer wg.Done() - link, account, err := r.GetDownloadLink(t, &file) + link, err := r.GetDownloadLink(t, &file) if err != nil { mu.Lock() if firstErr == nil { @@ -608,7 +608,7 @@ func (r *RealDebrid) GetFileDownloadLinks(t *types.Torrent) error { } file.DownloadLink = link - r.accounts.SetDownloadLink(account, link) + r.accounts.SetDownloadLink(link) mu.Lock() files[file.Name] = file @@ -701,6 +701,8 @@ func (r *RealDebrid) getDownloadLink(account *types.Account, file *types.File) ( } now := time.Now() return &types.DownloadLink{ + MaskedToken: account.MaskedToken, + Token: account.Token, Filename: data.Filename, Size: data.Filesize, Link: data.Link, @@ -711,14 +713,13 @@ func (r *RealDebrid) getDownloadLink(account *types.Account, file *types.File) ( } -func (r *RealDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, *types.Account, error) { - +func (r *RealDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, error) { accounts := r.accounts.Active() for _, account := range accounts { downloadLink, err := r.getDownloadLink(account, file) if err == nil { - return downloadLink, account, nil + return downloadLink, nil } retries := 0 @@ -727,16 +728,16 @@ func (r *RealDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types retries = 5 } else { // If the error is not traffic exceeded, return the error - return nil, account, err + return nil, err } backOff := 1 * time.Second for retries > 0 { downloadLink, err = r.getDownloadLink(account, file) if err == nil { - return downloadLink, account, nil + return downloadLink, nil } if !errors.Is(err, utils.TrafficExceededError) { - return nil, account, err + return nil, err } // Add a delay before retrying time.Sleep(backOff) @@ -744,7 +745,7 @@ func (r *RealDebrid) GetDownloadLink(t *types.Torrent, file *types.File) (*types retries-- } } - return nil, nil, fmt.Errorf("realdebrid API error: download link not found") + return nil, fmt.Errorf("realdebrid API error: download link not found") } func (r *RealDebrid) getTorrents(offset int, limit int) (int, []*types.Torrent, error) { @@ -870,7 +871,7 @@ func (r *RealDebrid) RefreshDownloadLinks() error { offset += len(dl) } - r.accounts.SetDownloadLinks(account, links) + r.accounts.SetDownloadLinks(links) } return nil } @@ -980,7 +981,7 @@ func (r *RealDebrid) SyncAccounts() error { } for _, account := range r.accounts.All() { if err := r.syncAccount(account); err != nil { - r.logger.Error().Err(err).Msgf("Error syncing account %s", account.Username) + r.logger.Error().Err(err).Str("account", account.MaskedToken).Msgf("Error syncing account %s", account.Username) continue // Skip this account and continue with the next } } diff --git a/pkg/debrid/providers/torbox/torbox.go b/pkg/debrid/providers/torbox/torbox.go index bd850f6..04fdbc7 100644 --- a/pkg/debrid/providers/torbox/torbox.go +++ b/pkg/debrid/providers/torbox/torbox.go @@ -411,7 +411,7 @@ func (tb *Torbox) GetFileDownloadLinks(t *types.Torrent) error { for _, file := range t.Files { go func() { defer wg.Done() - link, _, err := tb.GetDownloadLink(t, &file) + link, err := tb.GetDownloadLink(t, &file) if err != nil { errCh <- err return @@ -439,7 +439,7 @@ func (tb *Torbox) GetFileDownloadLinks(t *types.Torrent) error { // Collect download links for link := range linkCh { if link != nil { - tb.accounts.SetDownloadLink(nil, link) + tb.accounts.SetDownloadLink(link) } } @@ -454,7 +454,7 @@ func (tb *Torbox) GetFileDownloadLinks(t *types.Torrent) error { return nil } -func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, *types.Account, error) { +func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.DownloadLink, error) { url := fmt.Sprintf("%s/api/torrents/requestdl/", tb.Host) query := gourl.Values{} query.Add("torrent_id", t.Id) @@ -470,7 +470,7 @@ func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.Do Str("torrent_id", t.Id). Str("file_id", file.Id). Msg("Failed to make request to Torbox API") - return nil, nil, err + return nil, err } var data DownloadLinksResponse @@ -480,7 +480,7 @@ func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.Do Str("torrent_id", t.Id). Str("file_id", file.Id). Msg("Failed to unmarshal Torbox API response") - return nil, nil, err + return nil, err } if data.Data == nil { @@ -491,7 +491,7 @@ func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.Do Interface("error", data.Error). Str("detail", data.Detail). Msg("Torbox API returned no data") - return nil, nil, fmt.Errorf("error getting download links") + return nil, fmt.Errorf("error getting download links") } link := *data.Data @@ -500,7 +500,7 @@ func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.Do Str("torrent_id", t.Id). Str("file_id", file.Id). Msg("Torbox API returned empty download link") - return nil, nil, fmt.Errorf("error getting download links") + return nil, fmt.Errorf("error getting download links") } now := time.Now() @@ -510,9 +510,11 @@ func (tb *Torbox) GetDownloadLink(t *types.Torrent, file *types.File) (*types.Do Id: file.Id, Generated: now, ExpiresAt: now.Add(tb.autoExpiresLinksAfter), + Token: tb.APIKey, + MaskedToken: utils.Mask(tb.APIKey), } - return downloadLink, nil, nil + return downloadLink, nil } func (tb *Torbox) GetDownloadingStatus() []string { diff --git a/pkg/debrid/store/download_link.go b/pkg/debrid/store/download_link.go index 50f8de5..bb9f05b 100644 --- a/pkg/debrid/store/download_link.go +++ b/pkg/debrid/store/download_link.go @@ -30,22 +30,21 @@ func (r *downloadLinkRequest) Wait() (string, error) { return r.result, r.err } -func (c *Cache) GetDownloadLink(torrentName, filename, fileLink string) (string, error) { +func (c *Cache) GetDownloadLink(torrentName, filename, fileLink string) (*types.DownloadLink, error) { // Check link cache - if dl, err := c.checkDownloadLink(fileLink); dl != "" && err == nil { + if dl, err := c.checkDownloadLink(fileLink); dl != nil && err == nil { return dl, nil } dl, err := c.fetchDownloadLink(torrentName, filename, fileLink) if err != nil { - return "", err + return dl, err } if dl == nil || dl.DownloadLink == "" { - err = fmt.Errorf("download link is empty for %s in torrent %s", filename, torrentName) - return "", err + return nil, fmt.Errorf("download link is empty for %s in torrent %s", filename, torrentName) } - return dl.DownloadLink, err + return dl, nil } func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*types.DownloadLink, error) { @@ -86,11 +85,11 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type } c.logger.Trace().Msgf("Getting download link for %s(%s)", filename, file.Link) - downloadLink, account, err := c.client.GetDownloadLink(ct.Torrent, &file) + downloadLink, err := c.client.GetDownloadLink(ct.Torrent, &file) if err != nil { if errors.Is(err, utils.HosterUnavailableError) { c.logger.Trace(). - Str("account", account.Username). + Str("account", downloadLink.MaskedToken). Str("filename", filename). Str("torrent_id", ct.Id). Msg("Hoster unavailable, attempting to reinsert torrent") @@ -105,7 +104,7 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type return nil, fmt.Errorf("file %s not found in reinserted torrent %s", filename, torrentName) } // Retry getting the download link - downloadLink, account, err = c.client.GetDownloadLink(ct.Torrent, &file) + downloadLink, err = c.client.GetDownloadLink(ct.Torrent, &file) if err != nil { return nil, fmt.Errorf("retry failed to get download link: %w", err) } @@ -125,7 +124,7 @@ func (c *Cache) fetchDownloadLink(torrentName, filename, fileLink string) (*type } // Set link to cache - go c.client.Accounts().SetDownloadLink(account, downloadLink) + go c.client.Accounts().SetDownloadLink(downloadLink) return downloadLink, nil } @@ -136,25 +135,30 @@ func (c *Cache) GetFileDownloadLinks(t CachedTorrent) { } } -func (c *Cache) checkDownloadLink(link string) (string, error) { +func (c *Cache) checkDownloadLink(link string) (*types.DownloadLink, error) { - dl, _, err := c.client.Accounts().GetDownloadLink(link) + dl, err := c.client.Accounts().GetDownloadLink(link) if err != nil { - return "", err + return nil, err } if !c.downloadLinkIsInvalid(dl.DownloadLink) { - return dl.DownloadLink, nil + return dl, nil } - return "", fmt.Errorf("download link not found for %s", link) + return nil, fmt.Errorf("download link not found for %s", link) } -func (c *Cache) MarkDownloadLinkAsInvalid(link, downloadLink, reason string) { - c.invalidDownloadLinks.Store(downloadLink, reason) +func (c *Cache) MarkDownloadLinkAsInvalid(link string, downloadLink *types.DownloadLink, reason string) { + c.invalidDownloadLinks.Store(downloadLink.DownloadLink, reason) // Remove the download api key from active if reason == "bandwidth_exceeded" { // Disable the account account, err := c.client.Accounts().GetAccountFromLink(link) if err != nil { + maskedToken := "" + if account != nil { + maskedToken = account.MaskedToken + } + c.logger.Warn().Err(err).Str("account", maskedToken).Str("link", link).Msg("Failed to mark download link as invalid") return } c.client.Accounts().Disable(account) diff --git a/pkg/debrid/types/account.go b/pkg/debrid/types/account.go index b095bd8..793da4e 100644 --- a/pkg/debrid/types/account.go +++ b/pkg/debrid/types/account.go @@ -1,7 +1,9 @@ package types import ( + "fmt" "github.com/sirrobot01/decypharr/internal/config" + "github.com/sirrobot01/decypharr/internal/utils" "slices" "sync" "sync/atomic" @@ -37,6 +39,7 @@ type Account struct { Disabled bool InUse bool Token string `json:"token"` + MaskedToken string `json:"masked_token"` links map[string]*DownloadLink mu sync.RWMutex TrafficUsed int64 `json:"traffic_used"` // Traffic used in bytes @@ -95,13 +98,12 @@ func (a *Accounts) Current() *Account { return current } current = activeAccounts[0] - a.setCurrent(current) - return current + return a.setCurrent(current) } -func (a *Accounts) setCurrent(account *Account) { +func (a *Accounts) setCurrent(account *Account) *Account { if account == nil { - return + return nil } // Set every account InUse to false a.accounts.Range(func(key, value interface{}) bool { @@ -114,25 +116,24 @@ func (a *Accounts) setCurrent(account *Account) { }) account.InUse = true a.current.Store(account) + return account } func (a *Accounts) Disable(account *Account) { account.Disabled = true + account.InUse = false a.accounts.Store(account.Token, account) current := a.getCurrent() if current.Equals(account) { var newCurrent *Account - - a.accounts.Range(func(key, value interface{}) bool { - acc, ok := value.(*Account) - if ok && !acc.Disabled { - newCurrent = acc - return false // Break the loop - } - return true // Continue the loop - }) + activeAccounts := a.Active() + if len(activeAccounts) > 0 { + newCurrent = activeAccounts[0] + } else { + newCurrent = a.All()[0] + } a.setCurrent(newCurrent) } } @@ -155,19 +156,20 @@ func (a *Accounts) Reset() { a.setCurrent(current) } -func (a *Accounts) GetDownloadLink(fileLink string) (*DownloadLink, *Account, error) { +func (a *Accounts) GetDownloadLink(fileLink string) (*DownloadLink, error) { current := a.Current() if current == nil { - return nil, nil, NoActiveAccountsError + return nil, NoActiveAccountsError } - dl, ok := current.getLink(fileLink) + dl, ok := current.GetDownloadLink(fileLink) if !ok { - return nil, current, NoDownloadLinkError + return nil, NoDownloadLinkError } - if err := dl.Valid(); err != nil { - return nil, current, err + if !dl.Valid() { + return nil, fmt.Errorf("invalid download link: %s", dl.Link) } - return dl, current, nil + dl.Token = current.Token + return dl, nil } func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) { @@ -175,7 +177,7 @@ func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) { if currentAccount == nil { return nil, NoActiveAccountsError } - dl, ok := currentAccount.getLink(fileLink) + dl, ok := currentAccount.GetDownloadLink(fileLink) if !ok { return nil, NoDownloadLinkError } @@ -186,13 +188,22 @@ func (a *Accounts) GetAccountFromLink(fileLink string) (*Account, error) { } // SetDownloadLink sets the download link for the current account -func (a *Accounts) SetDownloadLink(account *Account, dl *DownloadLink) { +func (a *Accounts) SetDownloadLink(dl *DownloadLink) { if dl == nil { return } + var account *Account + // Get account from link token + if dl.Token != "" { + + if acc, ok := a.accounts.Load(dl.Token); ok { + account = acc.(*Account) + } + } if account == nil { account = a.getCurrent() } + account.setLink(dl.Link, dl) } @@ -210,12 +221,11 @@ func (a *Accounts) GetLinksCount() int { return a.Current().LinksCount() } -func (a *Accounts) SetDownloadLinks(account *Account, links map[string]*DownloadLink) { - if account == nil { - account = a.Current() +func (a *Accounts) SetDownloadLinks(links map[string]*DownloadLink) { + if a.Current() == nil { + return } - account.setLinks(links) - a.accounts.Store(account.Token, account) + a.Current().setLinks(links) } func (a *Accounts) Update(account *Account) { @@ -227,10 +237,11 @@ func (a *Accounts) Update(account *Account) { func newAccount(debridName, token string, index int) *Account { return &Account{ - Debrid: debridName, - Token: token, - Order: index, - links: make(map[string]*DownloadLink), + Debrid: debridName, + Token: token, + MaskedToken: utils.Mask(token), + Order: index, + links: make(map[string]*DownloadLink), } } @@ -241,7 +252,7 @@ func (a *Account) Equals(other *Account) bool { return a.Token == other.Token && a.Debrid == other.Debrid } -func (a *Account) getLink(fileLink string) (*DownloadLink, bool) { +func (a *Account) GetDownloadLink(fileLink string) (*DownloadLink, bool) { a.mu.RLock() defer a.mu.RUnlock() dl, ok := a.links[a.sliceFileLink(fileLink)] @@ -273,7 +284,7 @@ func (a *Account) setLinks(links map[string]*DownloadLink) { a.mu.Lock() defer a.mu.Unlock() for _, dl := range links { - if err := dl.Valid(); err != nil { + if !dl.Valid() { continue } a.links[a.sliceFileLink(dl.Link)] = dl diff --git a/pkg/debrid/types/client.go b/pkg/debrid/types/client.go index 6aeff7f..41aea21 100644 --- a/pkg/debrid/types/client.go +++ b/pkg/debrid/types/client.go @@ -8,7 +8,7 @@ type Client interface { SubmitMagnet(tr *Torrent) (*Torrent, error) CheckStatus(tr *Torrent) (*Torrent, error) GetFileDownloadLinks(tr *Torrent) error - GetDownloadLink(tr *Torrent, file *File) (*DownloadLink, *Account, error) + GetDownloadLink(tr *Torrent, file *File) (*DownloadLink, error) DeleteTorrent(torrentId string) error IsAvailable(infohashes []string) map[string]bool GetDownloadUncached() bool diff --git a/pkg/debrid/types/torrent.go b/pkg/debrid/types/torrent.go index b5de18e..dd45f6c 100644 --- a/pkg/debrid/types/torrent.go +++ b/pkg/debrid/types/torrent.go @@ -176,17 +176,19 @@ type DownloadLink struct { Generated time.Time `json:"generated"` Size int64 `json:"size"` Id string `json:"id"` - ExpiresAt time.Time + ExpiresAt time.Time `json:"expires_at"` + MaskedToken string `json:"masked_token"` + Token string `json:"token"` // The token or api key used to generate this link } -func (dl *DownloadLink) Valid() error { +func (dl *DownloadLink) Valid() bool { if dl.DownloadLink == "" { - return EmptyDownloadLinkError + return false } if dl.ExpiresAt.IsZero() || dl.ExpiresAt.Before(time.Now()) { - return DownloadLinkExpiredError + return false } - return nil + return true } func (dl *DownloadLink) String() string { diff --git a/pkg/server/debug.go b/pkg/server/debug.go index c889463..cded44d 100644 --- a/pkg/server/debug.go +++ b/pkg/server/debug.go @@ -123,21 +123,11 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) { accounts := client.Accounts().All() accountDetails := make([]map[string]any, 0) for _, account := range accounts { - // Mask token - show first 8 characters and last 4 characters - maskedToken := "" - if len(account.Token) > 12 { - maskedToken = account.Token[:8] + "****" + account.Token[len(account.Token)-4:] - } else if len(account.Token) > 8 { - maskedToken = account.Token[:4] + "****" + account.Token[len(account.Token)-2:] - } else { - maskedToken = "****" - } - accountDetail := map[string]any{ "order": account.Order, "disabled": account.Disabled, "in_use": account.InUse, - "token_masked": maskedToken, + "masked_token": account.MaskedToken, "username": account.Username, "traffic_used": account.TrafficUsed, "links_count": account.LinksCount(), diff --git a/pkg/web/templates/stats.html b/pkg/web/templates/stats.html index 03042d1..fabdf7b 100644 --- a/pkg/web/templates/stats.html +++ b/pkg/web/templates/stats.html @@ -390,7 +390,7 @@