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 }