@@ -2,12 +2,16 @@ package store
22
33import (
44 "archive/tar"
5+ "archive/zip"
6+ "bufio"
7+ "bytes"
58 _ "crypto/sha256" // ensure ids can be computed
69 "encoding/json"
710 "errors"
811 "fmt"
912 "io"
1013 "io/ioutil"
14+ "net/http"
1115 "path"
1216 "path/filepath"
1317 "strings"
@@ -259,12 +263,44 @@ func Export(name string, s Reader) io.ReadCloser {
259263 return reader
260264}
261265
266+ const (
267+ maxAllowedFileSizeToImport int64 = 10 << 20
268+ zipType string = "application/zip"
269+ )
270+
271+ func getImportContentType (r * bufio.Reader ) (string , error ) {
272+ head , err := r .Peek (512 )
273+ if err != nil && err != io .EOF {
274+ return "" , err
275+ }
276+
277+ return http .DetectContentType (head ), nil
278+ }
279+
262280// Import imports an exported context into a store
263281func Import (name string , s Writer , reader io.Reader ) error {
264- tr := tar .NewReader (reader )
282+ // Buffered reader will not advance the buffer, needed to determine content type
283+ r := bufio .NewReader (reader )
284+
285+ importContentType , err := getImportContentType (r )
286+ if err != nil {
287+ return err
288+ }
289+ switch importContentType {
290+ case zipType :
291+ return importZip (name , s , r )
292+ default :
293+ // Assume it's a TAR (TAR does not have a "magic number")
294+ return importTar (name , s , r )
295+ }
296+ }
297+
298+ func importTar (name string , s Writer , reader io.Reader ) error {
299+ tr := tar .NewReader (& LimitedReader {R : reader , N : maxAllowedFileSizeToImport })
265300 tlsData := ContextTLSData {
266301 Endpoints : map [string ]EndpointTLSData {},
267302 }
303+
268304 for {
269305 hdr , err := tr .Next ()
270306 if err == io .EOF {
@@ -282,37 +318,112 @@ func Import(name string, s Writer, reader io.Reader) error {
282318 if err != nil {
283319 return err
284320 }
285- var meta Metadata
286- if err := json . Unmarshal ( data , & meta ); err != nil {
321+ meta , err := parseMetadata ( data , name )
322+ if err != nil {
287323 return err
288324 }
289- meta .Name = name
290325 if err := s .CreateOrUpdate (meta ); err != nil {
291326 return err
292327 }
293328 } else if strings .HasPrefix (hdr .Name , "tls/" ) {
294- relative := strings .TrimPrefix (hdr .Name , "tls/" )
295- parts := strings .SplitN (relative , "/" , 2 )
296- if len (parts ) != 2 {
297- return errors .New ("archive format is invalid" )
298- }
299- endpointName := parts [0 ]
300- fileName := parts [1 ]
301329 data , err := ioutil .ReadAll (tr )
302330 if err != nil {
303331 return err
304332 }
305- if _ , ok := tlsData .Endpoints [endpointName ]; ! ok {
306- tlsData .Endpoints [endpointName ] = EndpointTLSData {
307- Files : map [string ][]byte {},
308- }
333+ if err := importEndpointTLS (& tlsData , hdr .Name , data ); err != nil {
334+ return err
335+ }
336+ }
337+ }
338+
339+ return s .ResetTLSMaterial (name , & tlsData )
340+ }
341+
342+ func importZip (name string , s Writer , reader io.Reader ) error {
343+ body , err := ioutil .ReadAll (& LimitedReader {R : reader , N : maxAllowedFileSizeToImport })
344+ if err != nil {
345+ return err
346+ }
347+ zr , err := zip .NewReader (bytes .NewReader (body ), int64 (len (body )))
348+ if err != nil {
349+ return err
350+ }
351+ tlsData := ContextTLSData {
352+ Endpoints : map [string ]EndpointTLSData {},
353+ }
354+
355+ for _ , zf := range zr .File {
356+ fi := zf .FileInfo ()
357+ if fi .IsDir () {
358+ // skip this entry, only taking files into account
359+ continue
360+ }
361+ if zf .Name == metaFile {
362+ f , err := zf .Open ()
363+ if err != nil {
364+ return err
365+ }
366+
367+ data , err := ioutil .ReadAll (& LimitedReader {R : f , N : maxAllowedFileSizeToImport })
368+ defer f .Close ()
369+ if err != nil {
370+ return err
371+ }
372+ meta , err := parseMetadata (data , name )
373+ if err != nil {
374+ return err
375+ }
376+ if err := s .CreateOrUpdate (meta ); err != nil {
377+ return err
378+ }
379+ } else if strings .HasPrefix (zf .Name , "tls/" ) {
380+ f , err := zf .Open ()
381+ if err != nil {
382+ return err
383+ }
384+ data , err := ioutil .ReadAll (f )
385+ defer f .Close ()
386+ if err != nil {
387+ return err
388+ }
389+ err = importEndpointTLS (& tlsData , zf .Name , data )
390+ if err != nil {
391+ return err
309392 }
310- tlsData .Endpoints [endpointName ].Files [fileName ] = data
311393 }
312394 }
395+
313396 return s .ResetTLSMaterial (name , & tlsData )
314397}
315398
399+ func parseMetadata (data []byte , name string ) (Metadata , error ) {
400+ var meta Metadata
401+ if err := json .Unmarshal (data , & meta ); err != nil {
402+ return meta , err
403+ }
404+ meta .Name = name
405+ return meta , nil
406+ }
407+
408+ func importEndpointTLS (tlsData * ContextTLSData , path string , data []byte ) error {
409+ parts := strings .SplitN (strings .TrimPrefix (path , "tls/" ), "/" , 2 )
410+ if len (parts ) != 2 {
411+ // TLS endpoints require archived file directory with 2 layers
412+ // i.e. tls/{endpointName}/{fileName}
413+ return errors .New ("archive format is invalid" )
414+ }
415+
416+ epName := parts [0 ]
417+ fileName := parts [1 ]
418+ if _ , ok := tlsData .Endpoints [epName ]; ! ok {
419+ tlsData .Endpoints [epName ] = EndpointTLSData {
420+ Files : map [string ][]byte {},
421+ }
422+ }
423+ tlsData .Endpoints [epName ].Files [fileName ] = data
424+ return nil
425+ }
426+
316427type setContextName interface {
317428 setContext (name string )
318429}
0 commit comments