// // Copyright (c) SAS Institute Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package vsix import ( "crypto" "encoding/xml" "fmt" "io/ioutil" "path" "github.com/sassoftware/relic/lib/certloader" ) type oxfRelationships struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"` Relationship []oxfRelationship } type oxfRelationship struct { Target string `xml:",attr"` Id string `xml:",attr"` Type string `xml:",attr"` } func readZip(files zipFiles, path string) ([]byte, error) { zf := files[path] if zf == nil { return nil, fmt.Errorf("file missing from zip: %s", path) } f, err := zf.Open() if err != nil { return nil, fmt.Errorf("failed to read zip file %s: %s", path, err) } return ioutil.ReadAll(f) } func parseRels(files zipFiles, path string) (*oxfRelationships, error) { blob, err := readZip(files, path) if err != nil { return nil, err } rels := new(oxfRelationships) if err := xml.Unmarshal(blob, rels); err != nil { return nil, fmt.Errorf("error parsing rels: %s", err) } return rels, nil } func (rels *oxfRelationships) Find(rType string) string { for _, rel := range rels.Relationship { if rel.Type == rType { return path.Clean("./" + rel.Target) } } return "" } func (rels *oxfRelationships) Append(zipPath, relType string) { d := crypto.SHA1.New() d.Write([]byte(zipPath)) d.Write([]byte(relType)) rel := oxfRelationship{Target: path.Clean("/" + zipPath), Type: relType} for { rel.Id = fmt.Sprintf("R%X", d.Sum(nil)[:4]) ok := true for _, rel2 := range rels.Relationship { if rel2.Id == rel.Id { ok = false } } if ok { break } d.Write([]byte{0}) } rels.Relationship = append(rels.Relationship, rel) } func (rels *oxfRelationships) Marshal() ([]byte, error) { x, err := xml.Marshal(rels) if err != nil { return nil, err } ret := make([]byte, len(xml.Header), len(xml.Header)+len(x)) copy(ret, xml.Header) ret = append(ret, x...) return ret, nil } func relPath(fp string) string { base := path.Base(fp) if base == "." { base = "" } return path.Join(path.Dir(fp), "_rels", base+".rels") } func (m *mangler) addFile(name string, contents []byte) error { d := m.hash.New() d.Write(contents) m.digests[name] = d.Sum(nil) return m.m.NewFile(name, contents) } func (m *mangler) newRels(parent, child, relType string) error { var rels oxfRelationships rels.Append(child, relType) contents, err := rels.Marshal() if err != nil { return err } return m.addFile(relPath(parent), contents) } func (m *mangler) addOrigin() error { return m.addFile(originPath, nil) } func (m *mangler) addCerts(cert *certloader.Certificate, sigName string) error { // NB: neither the certs nor the rels file are part of the signature, so // bypass m.digests and just call NewFile directly var rels oxfRelationships for _, chain := range cert.Chain() { certpath := path.Join(xmlCertPath, calcFileName(chain)+".cer") if err := m.m.NewFile(certpath, chain.Raw); err != nil { return err } rels.Append(certpath, certType) } contents, err := rels.Marshal() if err != nil { return err } return m.m.NewFile(relPath(sigName), contents) }