2021-12-19 21:39:53 +00:00
|
|
|
package processor
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
filelib "github.com/trustwallet/assets-go-libs/file"
|
2021-12-20 15:03:08 +00:00
|
|
|
"github.com/trustwallet/assets-go-libs/path"
|
|
|
|
"github.com/trustwallet/assets-go-libs/validation"
|
|
|
|
"github.com/trustwallet/assets-go-libs/validation/info"
|
|
|
|
"github.com/trustwallet/assets-go-libs/validation/list"
|
2022-01-16 14:13:01 +00:00
|
|
|
"github.com/trustwallet/assets-go-libs/validation/tokenlist"
|
2021-12-19 21:39:53 +00:00
|
|
|
"github.com/trustwallet/assets/internal/config"
|
|
|
|
"github.com/trustwallet/assets/internal/file"
|
|
|
|
"github.com/trustwallet/go-primitives/coin"
|
|
|
|
)
|
|
|
|
|
2022-01-07 13:02:59 +00:00
|
|
|
func (s *Service) ValidateJSON(f *file.AssetFile) error {
|
|
|
|
file, err := os.Open(f.Path())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
_, err = buf.ReadFrom(file)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-20 13:14:34 +00:00
|
|
|
err = validation.ValidateJSON(buf.Bytes())
|
2022-01-07 13:02:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-19 21:39:53 +00:00
|
|
|
func (s *Service) ValidateRootFolder(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(f.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateAllowedFiles(dirFiles, config.Default.ValidatorsSettings.RootFolder.AllowedFiles)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateChainFolder(f *file.AssetFile) error {
|
|
|
|
file, err := os.Open(f.Path())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
fileInfo, err := file.Stat()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var compErr = validation.NewErrComposite()
|
|
|
|
|
|
|
|
err = validation.ValidateLowercase(fileInfo.Name())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
dirFiles, err := file.ReadDir(0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateAllowedFiles(dirFiles, config.Default.ValidatorsSettings.ChainFolder.AllowedFiles)
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if compErr.Len() > 0 {
|
|
|
|
return compErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateImage(f *file.AssetFile) error {
|
|
|
|
var compErr = validation.NewErrComposite()
|
|
|
|
|
|
|
|
err := validation.ValidateLogoFileSize(f.Path())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Replace it with validation.ValidatePngImageDimension when "assets" repo is fixed.
|
2022-01-07 13:02:59 +00:00
|
|
|
// Read comments in ValidatePngImageDimensionForCI.
|
2021-12-19 21:39:53 +00:00
|
|
|
err = validation.ValidatePngImageDimensionForCI(f.Path())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if compErr.Len() > 0 {
|
|
|
|
return compErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateAssetFolder(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(f.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var compErr = validation.NewErrComposite()
|
|
|
|
|
|
|
|
err = validation.ValidateAllowedFiles(dirFiles, config.Default.ValidatorsSettings.AssetFolder.AllowedFiles)
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateAssetAddress(f.Chain(), f.Asset())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
errInfo := validation.ValidateHasFiles(dirFiles, []string{"info.json"})
|
|
|
|
errLogo := validation.ValidateHasFiles(dirFiles, []string{"logo.png"})
|
|
|
|
|
|
|
|
if errLogo != nil || errInfo != nil {
|
2022-01-31 14:11:27 +00:00
|
|
|
assetInfoPath := path.GetAssetInfoPath(f.Chain().Handle, f.Asset())
|
2021-12-19 21:39:53 +00:00
|
|
|
|
|
|
|
var infoJson info.AssetModel
|
2022-01-31 14:11:27 +00:00
|
|
|
if err = filelib.ReadJSONFile(assetInfoPath, &infoJson); err != nil {
|
2021-12-19 21:39:53 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if infoJson.GetStatus() != "spam" && infoJson.GetStatus() != "abandoned" {
|
|
|
|
compErr.Append(fmt.Errorf("%w: logo.png for non-spam assest", validation.ErrMissingFile))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if compErr.Len() > 0 {
|
|
|
|
return compErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateDappsFolder(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(f.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var compErr = validation.NewErrComposite()
|
2022-01-31 14:11:27 +00:00
|
|
|
|
2021-12-19 21:39:53 +00:00
|
|
|
for _, dirFile := range dirFiles {
|
|
|
|
err = validation.ValidateExtension(dirFile.Name(), config.Default.ValidatorsSettings.DappsFolder.Ext)
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateLowercase(dirFile.Name())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if compErr.Len() > 0 {
|
|
|
|
return compErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateChainInfoFile(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
var coinInfo info.CoinModel
|
|
|
|
if err := filelib.ReadJSONFile(f.Path(), &coinInfo); err != nil {
|
2021-12-19 21:39:53 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-20 13:51:37 +00:00
|
|
|
receivedTags, err := s.assetsManager.GetTagValues()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get tag values: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tags := make([]string, len(receivedTags.Tags))
|
|
|
|
for i, t := range receivedTags.Tags {
|
2021-12-19 21:39:53 +00:00
|
|
|
tags[i] = t.ID
|
|
|
|
}
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
err = info.ValidateCoin(coinInfo, tags)
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateAssetInfoFile(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
var assetInfo info.AssetModel
|
|
|
|
if err := filelib.ReadJSONFile(f.Path(), &assetInfo); err != nil {
|
2021-12-19 21:39:53 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
err := info.ValidateAsset(assetInfo, f.Chain(), f.Asset())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateValidatorsListFile(f *file.AssetFile) error {
|
|
|
|
if !isStackingChain(f.Chain()) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var model []list.Model
|
2022-01-31 14:11:27 +00:00
|
|
|
if err := filelib.ReadJSONFile(f.Path(), &model); err != nil {
|
2021-12-19 21:39:53 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
err := list.ValidateList(model)
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
listIDs := make([]string, len(model))
|
|
|
|
for i, listItem := range model {
|
|
|
|
listIDs[i] = *listItem.ID
|
|
|
|
}
|
|
|
|
|
2021-12-20 15:03:08 +00:00
|
|
|
assetsPath := path.GetValidatorAssetsPath(f.Chain().Handle)
|
2021-12-19 21:39:53 +00:00
|
|
|
assetFolder := s.fileService.GetAssetFile(assetsPath)
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(assetFolder.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
err = validation.ValidateAllowedFiles(dirFiles, listIDs)
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func isStackingChain(c coin.Coin) bool {
|
|
|
|
for _, stackingChain := range config.StackingChains {
|
|
|
|
if c.ID == stackingChain.ID {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateTokenListFile(f *file.AssetFile) error {
|
2022-02-03 20:36:45 +00:00
|
|
|
tokenListPath := f.Path()
|
|
|
|
tokenListExtendedPath := path.GetTokenListPath(f.Chain().Handle, path.TokenlistExtended)
|
|
|
|
|
|
|
|
return validateTokenList(tokenListPath, tokenListExtendedPath, f.Chain())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateTokenListExtendedFile(f *file.AssetFile) error {
|
|
|
|
tokenListPathExtended := f.Path()
|
|
|
|
tokenListPath := path.GetTokenListPath(f.Chain().Handle, path.TokenlistDefault)
|
|
|
|
|
|
|
|
return validateTokenList(tokenListPathExtended, tokenListPath, f.Chain())
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateTokenList(path1, path2 string, chain1 coin.Coin) error {
|
|
|
|
var tokenList1 tokenlist.Model
|
|
|
|
err := filelib.ReadJSONFile(path1, &tokenList1)
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-02-03 20:36:45 +00:00
|
|
|
if filelib.Exists(path2) {
|
|
|
|
var tokenList2 tokenlist.Model
|
|
|
|
err = filelib.ReadJSONFile(path2, &tokenList2)
|
2022-01-31 14:11:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-12-19 21:39:53 +00:00
|
|
|
|
2022-01-31 14:11:27 +00:00
|
|
|
tokensMap := make(map[string]bool)
|
2022-02-03 20:36:45 +00:00
|
|
|
for _, token := range tokenList2.Tokens {
|
2022-01-31 14:11:27 +00:00
|
|
|
tokensMap[token.Asset] = true
|
|
|
|
}
|
|
|
|
|
2022-02-03 20:36:45 +00:00
|
|
|
for _, token := range tokenList1.Tokens {
|
2022-01-31 14:11:27 +00:00
|
|
|
if _, exists := tokensMap[token.Asset]; exists {
|
|
|
|
return fmt.Errorf("duplicate asset: %s from %s, already exist in %s",
|
2022-02-03 20:36:45 +00:00
|
|
|
token.Asset, path1, path2)
|
2022-01-31 14:11:27 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-07 11:45:16 +00:00
|
|
|
}
|
|
|
|
|
2022-02-03 20:36:45 +00:00
|
|
|
err = tokenlist.ValidateTokenList(tokenList1, chain1, path1)
|
2022-01-10 12:32:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-12-19 21:39:53 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateInfoFolder(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(f.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateHasFiles(dirFiles, config.Default.ValidatorsSettings.ChainInfoFolder.HasFiles)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Service) ValidateValidatorsAssetFolder(f *file.AssetFile) error {
|
2022-01-31 14:11:27 +00:00
|
|
|
dirFiles, err := filelib.ReadDir(f.Path())
|
2021-12-19 21:39:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
compErr := validation.NewErrComposite()
|
|
|
|
err = validation.ValidateValidatorsAddress(f.Chain(), f.Asset())
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validation.ValidateHasFiles(dirFiles, config.Default.ValidatorsSettings.ChainValidatorsAssetFolder.HasFiles)
|
|
|
|
if err != nil {
|
|
|
|
compErr.Append(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if compErr.Len() > 0 {
|
|
|
|
return compErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|