github.com/LanceLRQ/deer-common@v0.0.9-0.20210319081233-e8222ac018a8/persistence/problems/reader_deer.go (about) 1 package problems 2 3 import ( 4 "archive/zip" 5 "bufio" 6 "bytes" 7 "crypto/rsa" 8 "encoding/binary" 9 "fmt" 10 "github.com/LanceLRQ/deer-common/constants" 11 "github.com/LanceLRQ/deer-common/persistence" 12 commonStructs "github.com/LanceLRQ/deer-common/structs" 13 "github.com/LanceLRQ/deer-common/utils" 14 "github.com/pkg/errors" 15 uuid "github.com/satori/go.uuid" 16 "golang.org/x/crypto/openpgp" 17 "io" 18 "os" 19 "path" 20 "reflect" 21 ) 22 23 // 解析判题结果 24 func parseProblemPackageBinary(reader io.Reader, unpackBody bool) (*ProblemPackage, error) { 25 // 校验魔数 26 magic := uint16(0) 27 if err := binary.Read(reader, binary.BigEndian, &magic); err != nil { 28 return nil, errors.Errorf("read file error: %s", err.Error()) 29 } 30 if magic != constants.ProblemPackageMagicCode { 31 return nil, errors.Errorf("not deer-executor problem package file") 32 } 33 // 开始解析package 34 pack := ProblemPackage{} 35 if err := binary.Read(reader, binary.BigEndian, &pack.Version); err != nil { 36 return nil, errors.Errorf("read [version] error: %s", err.Error()) 37 } 38 if err := binary.Read(reader, binary.BigEndian, &pack.CommitVersion); err != nil { 39 return nil, errors.Errorf("read [version] error: %s", err.Error()) 40 } 41 if err := binary.Read(reader, binary.BigEndian, &pack.ConfigSize); err != nil { 42 return nil, errors.Errorf("read [config size] error: %s", err.Error()) 43 } 44 if err := binary.Read(reader, binary.BigEndian, &pack.BodySize); err != nil { 45 return nil, errors.Errorf("read [body size] error: %s", err.Error()) 46 } 47 if err := binary.Read(reader, binary.BigEndian, &pack.CertSize); err != nil { 48 return nil, errors.Errorf("read [cert size] error: %s", err.Error()) 49 } 50 // 如果有证书 51 if pack.CertSize > 0 { 52 pack.Certificate = make([]byte, pack.CertSize) 53 if err := binary.Read(reader, binary.BigEndian, &pack.Certificate); err != nil { 54 return nil, errors.Errorf("read [cert public key] error: %s", err.Error()) 55 } 56 } 57 // 读取签名 58 if err := binary.Read(reader, binary.BigEndian, &pack.SignSize); err != nil { 59 return nil, errors.Errorf("read [sign size] error: %s", err.Error()) 60 } 61 pack.Signature = make([]byte, pack.SignSize) 62 if err := binary.Read(reader, binary.BigEndian, &pack.Signature); err != nil { 63 return nil, errors.Errorf("read [signature] error: %s", err.Error()) 64 } 65 // 读取Config 66 pack.Configs = make([]byte, pack.ConfigSize) 67 if err := binary.Read(reader, binary.BigEndian, &pack.Configs); err != nil { 68 return nil, errors.Errorf("read [config] error: %s", err.Error()) 69 } 70 if unpackBody { 71 // 理论上BodySize是多余的,剩下的都是body,这里就作为校验吧! 72 tmpBodyFileName := uuid.NewV1().String() + ".tmp.zip" 73 tmpBodyFilePath := path.Join("/tmp/", tmpBodyFileName) 74 pack.BodyPackageFile = tmpBodyFilePath 75 tmpBodyFile, err := os.Create(pack.BodyPackageFile) 76 if err != nil { 77 return nil, errors.Errorf("create body package temp file error: %s", err.Error()) 78 } 79 defer tmpBodyFile.Close() 80 if _, err := io.Copy(tmpBodyFile, reader); err != nil { 81 return nil, errors.Errorf("write body package temp file error: %s", err.Error()) 82 } 83 } 84 85 return &pack, nil 86 } 87 88 // 校验判题结果数据包 89 func validateProblemPackage(pack *ProblemPackage) (bool, error) { 90 // 打开临时文件 91 tmpBodyFile, err := os.Open(pack.BodyPackageFile) 92 if err != nil { 93 return false, errors.Errorf("open body package temp file error: %s", err.Error()) 94 } 95 defer tmpBodyFile.Close() 96 97 hash, err := persistence.SHA256Streams([]io.Reader{ 98 bytes.NewReader(pack.Configs), 99 tmpBodyFile, 100 }) 101 if err != nil { 102 return false, err 103 } 104 // 进行签名校验 105 if pack.CertSize > 0 { 106 // Read GPG Keys 107 elist, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(pack.Certificate)) 108 if err != nil { 109 return false, err 110 } 111 if len(elist) < 1 { 112 return false, errors.Errorf("GPG key error") 113 } 114 publicKey := elist[0].PrimaryKey.PublicKey.(*rsa.PublicKey) 115 err = persistence.RSA2048Verify(hash, pack.Signature, publicKey) 116 if err != nil { 117 return false, err 118 } 119 } else { 120 return reflect.DeepEqual(hash, pack.Signature), nil 121 } 122 return true, nil 123 } 124 125 func readProblemPackage(problemFile string, unpack bool) (*ProblemPackage, error) { 126 fp, err := os.Open(problemFile) 127 if err != nil { 128 return nil, errors.Errorf("open file (%s) error: %s", problemFile, err.Error()) 129 } 130 defer fp.Close() 131 132 reader := bufio.NewReader(fp) 133 pack, err := parseProblemPackageBinary(reader, unpack) 134 if err != nil { 135 return nil, err 136 } 137 138 return pack, nil 139 } 140 141 func doProblemPackageValidation(pack *ProblemPackage, validate bool) error { 142 ok, err := validateProblemPackage(pack) 143 var errmsg error 144 if !ok || err != nil { 145 if err != nil { 146 errmsg = errors.Errorf("validate package hash error: %s", err.Error()) 147 } 148 errmsg = errors.Errorf("validate package hash error") 149 } 150 // 如果出错并且现在必须要验证错误,则抛出 151 if errmsg != nil && validate { 152 return errmsg 153 } else { 154 fmt.Println("Warning! Package signature validation failed.") 155 } 156 return nil 157 } 158 159 // 读取题目信息 160 func ReadProblemInfo(problemFile string, unpack, validate bool, workDir string) (*commonStructs.JudgeConfiguration, string, error) { 161 pack, err := readProblemPackage(problemFile, unpack) 162 if err != nil { 163 return nil, "", err 164 } 165 config := commonStructs.JudgeConfiguration{} 166 utils.JSONBytesObject(pack.Configs, &config) 167 168 err = doProblemPackageValidation(pack, validate) 169 if err != nil { 170 return nil, "", err 171 } 172 173 if unpack { 174 zipReader, err := zip.OpenReader(pack.BodyPackageFile) 175 if err != nil { 176 return nil, "", errors.Errorf("open body file (%s) error: %s", problemFile, err.Error()) 177 } 178 defer zipReader.Close() 179 180 err = UnZip(zipReader, workDir) 181 if err != nil { 182 return nil, "", err 183 } 184 configFile := path.Join(workDir, "problem.json") 185 fp, err := os.Create(configFile) 186 if err != nil { 187 return nil, "", err 188 } 189 defer fp.Close() 190 _, err = fp.Write(pack.Configs) 191 if err != nil { 192 return nil, "", err 193 } 194 return &config, configFile, nil 195 } 196 197 return &config, "", nil 198 } 199 200 // 读取题目携带的GPG信息 201 func ReadProblemGPGInfo(problemFile string) (string, error) { 202 pack, err := readProblemPackage(problemFile, false) 203 if err != nil { 204 return "", err 205 } 206 207 err = doProblemPackageValidation(pack, false) 208 if err != nil { 209 return "", err 210 } 211 212 if pack.CertSize == 0 { 213 return "no GPG public key", nil 214 } else { 215 elist, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(pack.Certificate)) 216 if err != nil { 217 return "", err 218 } 219 if len(elist) < 1 { 220 return "", errors.Errorf("GPG key error") 221 } 222 rel := "" 223 for _, identify := range elist[0].Identities { 224 rel += identify.Name + "\n" 225 } 226 return rel, nil 227 } 228 }