-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
358 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/replicatedhq/embedded-cluster/pkg/embed" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
var embedCommand = &cli.Command{ | ||
Name: "embed", | ||
Usage: "Embeds data in the binary", | ||
Flags: []cli.Flag{ | ||
&cli.StringFlag{ | ||
Name: "binary-path", | ||
Usage: "Path to the binary", | ||
}, | ||
&cli.StringFlag{ | ||
Name: "binary-destination-path", | ||
Usage: "Path to write the binary with embedded data", | ||
}, | ||
&cli.StringFlag{ | ||
Name: "embed-path", | ||
Usage: "Path to the file to embed", | ||
}, | ||
&cli.StringFlag{ | ||
Name: "embed-delimiter", | ||
Usage: "Delimiter to use for embedding", | ||
}, | ||
}, | ||
Action: func(c *cli.Context) error { | ||
binaryPath := c.String("binary-path") | ||
if binaryPath == "" { | ||
return fmt.Errorf("binary-path is required") | ||
} | ||
|
||
binaryDestinationPath := c.String("binary-destination-path") | ||
if binaryDestinationPath == "" { | ||
return fmt.Errorf("binary-destination-path is required") | ||
} | ||
|
||
embedPath := c.String("embed-path") | ||
if embedPath == "" { | ||
return fmt.Errorf("embed-path is required") | ||
} | ||
|
||
embedDelimiter := c.String("embed-delimiter") | ||
if embedDelimiter == "" { | ||
return fmt.Errorf("embed-delimiter is required") | ||
} | ||
|
||
err := embed.EmbedInBinary(embedPath, embedDelimiter, binaryPath, binaryDestinationPath) | ||
if err != nil { | ||
return fmt.Errorf("fail to embed data in the binary: %w", err) | ||
} | ||
err = os.Chmod(binaryDestinationPath, 0755) | ||
if err != nil { | ||
return fmt.Errorf("fail to change permissions on the binary: %w", err) | ||
} | ||
|
||
fmt.Printf("Output binary with embedded data written to %s\n", binaryDestinationPath) | ||
return nil | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package embed | ||
|
||
import ( | ||
"bytes" | ||
"encoding/base64" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
) | ||
|
||
const ( | ||
ReleaseDelimiter = "APP RELEASE" | ||
ReleaseMetadataDelimiter = "RELEASE METADATA" | ||
|
||
beginDelimiterTemplate = "-----BEGIN %s-----" | ||
endDelimiterTemplate = "-----END %s-----" | ||
) | ||
|
||
// EmbedReleaseDataInBinary embeds the app release data in the binary at the end of the file and | ||
// writes the new binary to the output path. | ||
func EmbedReleaseDataInBinary(binPath string, embedPath string, outputPath string) error { | ||
return EmbedInBinary(embedPath, ReleaseDelimiter, binPath, outputPath) | ||
} | ||
|
||
// EmbedReleaseDataInBinaryReader embeds the app release data in the binary at the end of the | ||
// binary reader, and returns a new binary reader with the embedded app release data and the new | ||
// binary size. | ||
func EmbedReleaseDataInBinaryReader(binReader io.Reader, binSize int64, releaseData []byte) (io.Reader, int64) { | ||
return EmbedDataInBinaryReader(ReleaseDelimiter, releaseData, binReader, binSize) | ||
} | ||
|
||
// ExtractReleaseDataFromBinary extracts the app release data from the binary. | ||
func ExtractReleaseDataFromBinary(binPath string) ([]byte, error) { | ||
return ExtractDataFromBinary(ReleaseDelimiter, binPath) | ||
} | ||
|
||
// EmbedReleaseMetadataInBinary embeds the app release metadata in the binary at the end of the | ||
// file and writes the new binary to the output path. | ||
func EmbedReleaseMetadataInBinary(binPath string, embedPath string, outputPath string) error { | ||
return EmbedInBinary(embedPath, ReleaseMetadataDelimiter, binPath, outputPath) | ||
} | ||
|
||
// EmbedReleaseMetadataInBinaryReader embeds the release metadata in the binary at the end of the | ||
// binary reader, and returns a new binary reader with the embedded release metadata and the new | ||
// binary size. | ||
func EmbedReleaseMetadataInBinaryReader(binReader io.Reader, binSize int64, data []byte) (io.Reader, int64) { | ||
return EmbedDataInBinaryReader(ReleaseMetadataDelimiter, data, binReader, binSize) | ||
} | ||
|
||
// ExtractReleaseMetadataFromBinary extracts the release metadata from the binary. | ||
func ExtractReleaseMetadataFromBinary(binPath string) ([]byte, error) { | ||
return ExtractDataFromBinary(ReleaseMetadataDelimiter, binPath) | ||
} | ||
|
||
// EmbedInBinary embeds the data in the binary at the end of the file and writes the new binary to | ||
// the output path. | ||
func EmbedInBinary(embedPath string, delim string, binPath string, outputPath string) error { | ||
binContent, err := os.ReadFile(binPath) | ||
if err != nil { | ||
return fmt.Errorf("failed to read binary: %w", err) | ||
} | ||
|
||
start := bytes.Index(binContent, beginDelimiterBytes(delim)) | ||
end := bytes.Index(binContent, endDelimiterBytes(delim)) | ||
|
||
if start != -1 && end != -1 { | ||
// data is already embedded in the binary, remove it | ||
binContent = append(binContent[:start], binContent[end+len(endDelimiterBytes(delim)):]...) | ||
} | ||
|
||
binReader := bytes.NewReader(binContent) | ||
binSize := int64(len(binContent)) | ||
|
||
data, err := os.ReadFile(embedPath) | ||
if err != nil { | ||
return fmt.Errorf("failed to read data: %w", err) | ||
} | ||
|
||
newBinReader, totalLen := EmbedDataInBinaryReader(delim, data, binReader, binSize) | ||
newBinContent, err := io.ReadAll(newBinReader) | ||
if err != nil { | ||
return fmt.Errorf("failed to read new binary: %w", err) | ||
} | ||
if totalLen != int64(len(newBinContent)) { | ||
return fmt.Errorf("failed to read new binary: expected %d bytes, got %d", totalLen, len(newBinContent)) | ||
} | ||
|
||
if err := os.WriteFile(outputPath, newBinContent, 0644); err != nil { | ||
return fmt.Errorf("failed to write output: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// EmbedDataInBinaryReader embeds the data in the binary at the end of the binary reader, and | ||
// returns a new binary reader with the embedded data and the new binary size. | ||
func EmbedDataInBinaryReader(delim string, data []byte, binReader io.Reader, binSize int64) (io.Reader, int64) { | ||
encoded := base64.StdEncoding.EncodeToString(data) | ||
|
||
newBinSize := binSize | ||
newBinSize += int64(len(beginDelimiterBytes(delim))) | ||
newBinSize += int64(len(encoded)) | ||
newBinSize += int64(len(endDelimiterBytes(delim))) | ||
|
||
newBinReader := io.MultiReader( | ||
binReader, | ||
bytes.NewReader(beginDelimiterBytes(delim)), | ||
strings.NewReader(encoded), | ||
bytes.NewReader(endDelimiterBytes(delim)), | ||
) | ||
|
||
return newBinReader, newBinSize | ||
} | ||
|
||
// ExtractDataFromBinary extracts the data from the binary. | ||
func ExtractDataFromBinary(delim string, binPath string) ([]byte, error) { | ||
binContent, err := os.ReadFile(binPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read binary: %w", err) | ||
} | ||
|
||
start := bytes.Index(binContent, beginDelimiterBytes(delim)) | ||
if start == -1 { | ||
return nil, nil | ||
} | ||
|
||
end := bytes.Index(binContent, endDelimiterBytes(delim)) | ||
if end == -1 { | ||
return nil, fmt.Errorf("failed to find end delimiter in executable") | ||
} | ||
|
||
if start+len(beginDelimiterBytes(delim)) > len(binContent) { | ||
return nil, fmt.Errorf("invalid start delimiter") | ||
} else if start+len(beginDelimiterBytes(delim)) > end { | ||
return nil, fmt.Errorf("start delimter after end delimter") | ||
} else if end > len(binContent) { | ||
return nil, fmt.Errorf("invalid end delimiter") | ||
} | ||
|
||
encoded := binContent[start+len(beginDelimiterBytes(delim)) : end] | ||
|
||
decoded, err := base64.StdEncoding.DecodeString(string(encoded)) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to decode data: %w", err) | ||
} | ||
|
||
return decoded, nil | ||
} | ||
|
||
func beginDelimiterBytes(delim string) []byte { | ||
return []byte(fmt.Sprintf(beginDelimiterTemplate, delim)) | ||
} | ||
|
||
func endDelimiterBytes(delim string) []byte { | ||
return []byte(fmt.Sprintf(endDelimiterTemplate, delim)) | ||
} |
Oops, something went wrong.