github.com/LanceLRQ/deer-common@v0.0.9-0.20210319081233-e8222ac018a8/persistence/problems/reader_zip.go (about)

     1  package problems
     2  
     3  import (
     4  	"archive/zip"
     5  	"bufio"
     6  	"bytes"
     7  	"crypto/rsa"
     8  	"github.com/LanceLRQ/deer-common/persistence"
     9  	commonStructs "github.com/LanceLRQ/deer-common/structs"
    10  	"github.com/LanceLRQ/deer-common/utils"
    11  	"github.com/pkg/errors"
    12  	"golang.org/x/crypto/openpgp"
    13  	"io"
    14  	"io/ioutil"
    15  	"log"
    16  	"path"
    17  	"reflect"
    18  )
    19  
    20  // 校验判题结果数据包
    21  func validateProblemPackageZip(zipArchive *zip.ReadCloser) (bool, error) {
    22  	// 搜索config文件
    23  	configFile, _, err := FindInZip(zipArchive, "problem.json")
    24  	if err != nil {
    25  		return false, err
    26  	}
    27  
    28  	configBytes, err := ioutil.ReadAll(*configFile)
    29  	if err != nil {
    30  		return false, err
    31  	}
    32  
    33  	hash, err := persistence.SHA256Streams([]io.Reader{bytes.NewReader(configBytes)})
    34  	if err != nil {
    35  		return false, err
    36  	}
    37  
    38  	// signFile
    39  	signFile, _, err := FindInZip(zipArchive, ".sign")
    40  	if err != nil {
    41  		return false, err
    42  	}
    43  
    44  	signature, err := ioutil.ReadAll(*signFile)
    45  	if err != nil {
    46  		return false, err
    47  	}
    48  
    49  	// gpgFile
    50  	withGPG := true
    51  	gpgFile, _, err := FindInZip(zipArchive, ".gpg")
    52  	if err != nil {
    53  		withGPG = false
    54  	}
    55  
    56  	// 进行签名校验
    57  	if withGPG && gpgFile != nil {
    58  		// Read GPG Keys
    59  		elist, err := openpgp.ReadArmoredKeyRing(bufio.NewReader(*gpgFile))
    60  		if err != nil {
    61  			return false, err
    62  		}
    63  		if len(elist) < 1 {
    64  			return false, errors.Errorf("GPG key error")
    65  		}
    66  		publicKey := elist[0].PrimaryKey.PublicKey.(*rsa.PublicKey)
    67  		err = persistence.RSA2048Verify(hash, signature, publicKey)
    68  		if err != nil {
    69  			return false, err
    70  		}
    71  	} else {
    72  		return reflect.DeepEqual(hash, signature), nil
    73  	}
    74  	return true, nil
    75  }
    76  
    77  func doProblemPackageValidationZip(zipArchive *zip.ReadCloser, validate bool) error {
    78  	ok, err := validateProblemPackageZip(zipArchive)
    79  	var errmsg error
    80  	if !ok || err != nil {
    81  		if err != nil {
    82  			errmsg = errors.Errorf("validate package hash error: %s", err.Error())
    83  		}
    84  		errmsg = errors.Errorf("validate package hash error")
    85  	}
    86  	// 如果出错并且现在必须要验证错误,则抛出
    87  	if errmsg != nil {
    88  		if validate {
    89  			return errmsg
    90  		} else {
    91  			log.Println("Warning! Package signature validation failed.")
    92  		}
    93  	}
    94  	return nil
    95  }
    96  
    97  // 读取题目信息(ZIP)
    98  // workDir只在需要解压的时候才会用到
    99  func ReadProblemInfoZip(problemFile string, unpack, validate bool, workDir string) (*commonStructs.JudgeConfiguration, string, error) {
   100  	// 打开文件
   101  	zipReader, err := zip.OpenReader(problemFile)
   102  	if err != nil {
   103  		return nil, "", errors.Errorf("open file (%s) error: %s", problemFile, err.Error())
   104  	}
   105  	defer zipReader.Close()
   106  
   107  	config := commonStructs.JudgeConfiguration{}
   108  	// 搜索config文件
   109  	configFile, _, err := FindInZip(zipReader, "problem.json")
   110  	if err != nil {
   111  		return nil, "", err
   112  	}
   113  	// 读取Config信息
   114  	configByte, err := ioutil.ReadAll(*configFile)
   115  	if err != nil {
   116  		return nil, "", err
   117  	}
   118  	utils.JSONBytesObject(configByte, &config)
   119  	// 校验签名
   120  	err = doProblemPackageValidationZip(zipReader, validate)
   121  	if err != nil {
   122  		return nil, "", err
   123  	}
   124  
   125  	if unpack {
   126  		// 解压
   127  		err = UnZip(zipReader, workDir)
   128  		if err != nil {
   129  			return nil, "", err
   130  		}
   131  	}
   132  
   133  	return &config, path.Join(workDir, "problem.json"), nil
   134  }
   135  
   136  // 读取题目携带的GPG信息(ZIP)
   137  func ReadProblemGPGInfoZip(problemFile string) (string, error) {
   138  	zipReader, err := zip.OpenReader(problemFile)
   139  	if err != nil {
   140  		return "", errors.Errorf("open file (%s) error: %s", problemFile, err.Error())
   141  	}
   142  	defer zipReader.Close()
   143  
   144  	file, _, err := FindInZip(zipReader, ".gpg")
   145  	if err != nil {
   146  		if IsFileNotFoundError(err) {
   147  			return "", errors.Errorf("no GPG public key")
   148  		}
   149  		return "", err
   150  	}
   151  
   152  	elist, err := openpgp.ReadArmoredKeyRing(bufio.NewReader(*file))
   153  	if err != nil {
   154  		return "", err
   155  	}
   156  	if len(elist) < 1 {
   157  		return "", errors.Errorf("GPG key error")
   158  	}
   159  	rel := ""
   160  	for _, identify := range elist[0].Identities {
   161  		rel += identify.Name + "\n"
   162  	}
   163  	return rel, nil
   164  }