github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/subscription/subscriptionmanager/subdocupdater.go (about)

     1  package subscriptionmanager
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  	"unicode"
     8  
     9  	"golang.org/x/crypto/sha3"
    10  
    11  	"github.com/v2fly/v2ray-core/v5/app/subscription/containers"
    12  	"github.com/v2fly/v2ray-core/v5/app/subscription/documentfetcher"
    13  	"github.com/v2fly/v2ray-core/v5/app/subscription/specs"
    14  )
    15  
    16  func (s *SubscriptionManagerImpl) updateSubscription(subscriptionName string) error {
    17  	var trackedSub *trackedSubscription
    18  	if trackedSubFound, found := s.trackedSubscriptions[subscriptionName]; !found {
    19  		return newError("not found")
    20  	} else {
    21  		trackedSub = trackedSubFound
    22  	}
    23  	importSource := trackedSub.importSource
    24  	docFetcher, err := documentfetcher.GetFetcher("http")
    25  	if err != nil {
    26  		return newError("failed to get fetcher: ", err)
    27  	}
    28  	if strings.HasPrefix(importSource.Url, "data:") {
    29  		docFetcher, err = documentfetcher.GetFetcher("dataurl")
    30  		if err != nil {
    31  			return newError("failed to get fetcher: ", err)
    32  		}
    33  	}
    34  
    35  	downloadedDocument, err := docFetcher.DownloadDocument(s.ctx, importSource)
    36  	if err != nil {
    37  		return newError("failed to download document: ", err)
    38  	}
    39  
    40  	trackedSub.originalDocument = downloadedDocument
    41  
    42  	container, err := containers.TryAllParsers(trackedSub.originalDocument, "")
    43  	if err != nil {
    44  		return newError("failed to parse document: ", err)
    45  	}
    46  
    47  	trackedSub.originalContainer = container
    48  
    49  	parsedDocument := &specs.SubscriptionDocument{}
    50  	parsedDocument.Metadata = container.Metadata
    51  
    52  	trackedSub.originalServerConfig = make(map[string]*originalServerConfig)
    53  
    54  	for _, server := range trackedSub.originalContainer.ServerSpecs {
    55  		documentHash := sha3.Sum256(server.Content)
    56  		serverConfigHashName := fmt.Sprintf("%x", documentHash)
    57  		parsed, err := s.converter.TryAllConverters(server.Content, "outbound", server.KindHint)
    58  		if err != nil {
    59  			trackedSub.originalServerConfig["!!!"+serverConfigHashName] = &originalServerConfig{data: server.Content}
    60  			continue
    61  		}
    62  		s.polyfillServerConfig(parsed, serverConfigHashName)
    63  		parsedDocument.Server = append(parsedDocument.Server, parsed)
    64  		trackedSub.originalServerConfig[parsed.Id] = &originalServerConfig{data: server.Content}
    65  	}
    66  	newError("new subscription document fetched and parsed from ", subscriptionName).AtInfo().WriteToLog()
    67  	if err := s.applySubscriptionTo(subscriptionName, parsedDocument); err != nil {
    68  		return newError("failed to apply subscription: ", err)
    69  	}
    70  	trackedSub.currentDocument = parsedDocument
    71  	trackedSub.currentDocumentExpireTime = time.Now().Add(time.Second * time.Duration(importSource.DefaultExpireSeconds))
    72  	return nil
    73  }
    74  
    75  func (s *SubscriptionManagerImpl) polyfillServerConfig(document *specs.SubscriptionServerConfig, hash string) {
    76  	document.Id = hash
    77  
    78  	if document.Metadata == nil {
    79  		document.Metadata = make(map[string]string)
    80  	}
    81  
    82  	if id, ok := document.Metadata[ServerMetadataID]; !ok || id == "" {
    83  		document.Metadata[ServerMetadataID] = document.Id
    84  	} else {
    85  		document.Id = document.Metadata[ServerMetadataID]
    86  	}
    87  
    88  	if fqn, ok := document.Metadata[ServerMetadataFullyQualifiedName]; !ok || fqn == "" {
    89  		document.Metadata[ServerMetadataFullyQualifiedName] = hash
    90  	}
    91  
    92  	if tagName, ok := document.Metadata[ServerMetadataTagName]; !ok || tagName == "" {
    93  		document.Metadata[ServerMetadataTagName] = document.Metadata[ServerMetadataID]
    94  	}
    95  	document.Metadata[ServerMetadataTagName] = s.restrictTagName(document.Metadata[ServerMetadataTagName])
    96  }
    97  
    98  func (s *SubscriptionManagerImpl) restrictTagName(tagName string) string {
    99  	newTagName := &strings.Builder{}
   100  	somethingRemoved := false
   101  	for _, c := range tagName {
   102  		if (unicode.IsLetter(c) || unicode.IsNumber(c)) && c < 128 {
   103  			newTagName.WriteRune(c)
   104  		} else {
   105  			somethingRemoved = true
   106  		}
   107  	}
   108  	newTagNameString := newTagName.String()
   109  	if len(newTagNameString) > 24 {
   110  		newTagNameString = newTagNameString[:15]
   111  		somethingRemoved = true
   112  	}
   113  	if somethingRemoved {
   114  		hashedTagName := sha3.Sum256([]byte(tagName))
   115  		hashedTagNameString := fmt.Sprintf("%x", hashedTagName)
   116  		newTagNameString = newTagNameString + "_" + hashedTagNameString[:8]
   117  	}
   118  	return newTagNameString
   119  }