diff --git a/README.md b/README.md index a537fa3..c772757 100644 --- a/README.md +++ b/README.md @@ -35,22 +35,32 @@ runtime, interpreter or package manager should make the setup easier in the end. ## Usage +### Node.js + #### With specific version ```bash -nsd download /path/ --version 12.15.0 +nsd nodejs /path/ --version 12.15.0 ``` #### With specific version from file ```bash -nsd download /path/ --from-file ./node_version +nsd nodejs /path/ --from-file ./node_version ``` #### No specific version, will try reading from CWD/.nvmrc ```bash -nsd download /path/ +nsd nodejs /path/ +``` + +### Yarn (Currently only v1 supported) + +#### With specific version + +```bash +nsd yarn /path/ --version 1.22.5 ``` ## How to build diff --git a/go.mod b/go.mod index 8c4d6c9..92ead79 100644 --- a/go.mod +++ b/go.mod @@ -7,4 +7,5 @@ require ( github.com/gorilla/mux v1.8.0 github.com/mholt/archiver/v3 v3.5.0 github.com/spf13/cobra v1.1.1 + golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 ) diff --git a/go.sum b/go.sum index 152b95a..682c332 100644 --- a/go.sum +++ b/go.sum @@ -200,6 +200,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/nsd/checksum/gpg.go b/nsd/checksum/gpg.go new file mode 100644 index 0000000..4cb6ffd --- /dev/null +++ b/nsd/checksum/gpg.go @@ -0,0 +1,42 @@ +package checksum + +import ( + "fmt" + "golang.org/x/crypto/openpgp" + "os" +) + +// VerifyGPG is cool +func VerifyGPG(signatureFilePath string, keyFilePath string, tarFilePath string) (err error) { + keyFile, err := os.Open(keyFilePath) + if err != nil { + return + } + defer keyFile.Close() + + signatureFile, err := os.Open(signatureFilePath) + if err != nil { + return + } + defer signatureFile.Close() + + tarFile, err := os.Open(tarFilePath) + if err != nil { + fmt.Println(err) + return + } + defer tarFile.Close() + + keyring, err := openpgp.ReadArmoredKeyRing(keyFile) + if err != nil { + return + } + entity, err := openpgp.CheckArmoredDetachedSignature(keyring, tarFile, signatureFile) + if err != nil { + return + } + + fmt.Println(entity) + + return +} diff --git a/nsd/checksum/gpg_test.go b/nsd/checksum/gpg_test.go new file mode 100644 index 0000000..9e83412 --- /dev/null +++ b/nsd/checksum/gpg_test.go @@ -0,0 +1,10 @@ +package checksum + +import "testing" + +func TestVerifyGPGSignature(t *testing.T) { + err := VerifyGPG("./testdata/gpg/file.txt.asc", "./testdata/gpg/pubkey.gpg", "./testdata/gpg/file.txt") + if err != nil { + t.Errorf("TestVerifyGPGSignature() did error %s", err) + } +} diff --git a/nsd/checksum/testdata/gpg/file.txt b/nsd/checksum/testdata/gpg/file.txt new file mode 100644 index 0000000..a7f8d9e --- /dev/null +++ b/nsd/checksum/testdata/gpg/file.txt @@ -0,0 +1 @@ +bla diff --git a/nsd/checksum/testdata/gpg/file.txt.asc b/nsd/checksum/testdata/gpg/file.txt.asc new file mode 100644 index 0000000..9550bc6 --- /dev/null +++ b/nsd/checksum/testdata/gpg/file.txt.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNATURE----- + +iQGzBAABCgAdFiEEdv45keW9UbLASyCZEtrqfmodL+oFAl+8PcUACgkQEtrqfmod +L+rOUwv/d6LzM71SWxgZgtVyi3udfmtb0EkK92NzSzMxzVDRjGX6qQ8w+9x2YvAN +LsZyrrOHeHcUofyVUGg2P2aGFEcSl9mIjZw2qdfLEQqv+KZSjdMBwA4+HvWtGRUi +ApsldTbbWvilmmFEWMExVIIL1nUXPZO57Ha/1xupbNtCYlJMjntQq8JPARnsb8fL +kkAfJdIviBXzpxREjV2MDOA1SlbGqPHJZZ3dK+LBlyBRSNQjhxM6X+a59CIzZLUa +BGJ744nZFpvpuy2qpTOb0La6RBbbof42Ti6JfpscGcyPYvqkw2DCSWYqWUdUd6Jl +VtyUMLo9tWrbvZTp+9SyGFpNRkALuJ2/HU+iVDYYpY1VqZQLR1Lvs7docbuM2u2x +JNN3W24fkB7M9aXcqyCTjYeEUBZ1ClNyMwq7PP2t20aead3TTf3+Bzrdo9U/cTVN +tnGbinuxZxKHs18fOV5rXVAZTgzpquj37QugsSHPtMn9p1W22O60T4RmT+D6Qu65 +a9u8YDdZ +=3Tcr +-----END PGP SIGNATURE----- diff --git a/nsd/checksum/testdata/gpg/prvkey.gpg b/nsd/checksum/testdata/gpg/prvkey.gpg new file mode 100644 index 0000000..1c491af --- /dev/null +++ b/nsd/checksum/testdata/gpg/prvkey.gpg @@ -0,0 +1,83 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +=aPpU +-----END PGP PRIVATE KEY BLOCK----- diff --git a/nsd/checksum/testdata/gpg/pubkey.gpg b/nsd/checksum/testdata/gpg/pubkey.gpg new file mode 100644 index 0000000..4b48acc --- /dev/null +++ b/nsd/checksum/testdata/gpg/pubkey.gpg @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +wFJz1LW6o/+cBoEL3mBj7tSrVzP3R2UvDTkJpA== +=/K5H +-----END PGP PUBLIC KEY BLOCK----- diff --git a/nsd/cmd/download.go b/nsd/cmd/nodejs.go similarity index 68% rename from nsd/cmd/download.go rename to nsd/cmd/nodejs.go index 1a30746..5331a5e 100644 --- a/nsd/cmd/download.go +++ b/nsd/cmd/nodejs.go @@ -18,11 +18,11 @@ import ( ) var ( - version string - fromFile string - downloadCommand = &cobra.Command{ - Use: "download [path]", - Short: "Download nodejs to specific folder", + nodejsVersion string + nodejsVersionfromFile string + nodejsCommand = &cobra.Command{ + Use: "nodejs [path]", + Short: "Download Node.js to specific folder", Long: "", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { @@ -33,19 +33,19 @@ var ( RunE: func(cmd *cobra.Command, args []string) (err error) { downloadPath := args[0] - err = prepareFlags() + err = prepareNodejsFlags() if err != nil { return } - nodeURL := fmt.Sprintf(string(NodeJs.CurrentURL)+"node-v%s-%s.%s", version, version, NodeJs.CurrentArch, NodeJs.CurrentExtension) + nodeURL := fmt.Sprintf(string(NodeJs.CurrentURL)+"node-v%s-%s.%s", nodejsVersion, nodejsVersion, NodeJs.CurrentArch, NodeJs.CurrentExtension) nodeFilePath, err := Download.File(nodeURL) if err != nil { return } defer os.Remove(nodeFilePath) - checksumURL := fmt.Sprintf(string(NodeJs.CurrentURL)+"SHASUMS256.txt", version) + checksumURL := fmt.Sprintf(string(NodeJs.CurrentURL)+"SHASUMS256.txt", nodejsVersion) checkusmFilePath, err := Download.File(checksumURL) if err != nil { return @@ -96,23 +96,23 @@ var ( } ) -func prepareFlags() (err error) { - if version != "" && fromFile != "" { +func prepareNodejsFlags() (err error) { + if nodejsVersion != "" && nodejsVersionfromFile != "" { return errors.New("cannot figure out which version to install. Please only specify one of --version or --from-file") } versionSpecified := true - if version == "" && fromFile == "" { + if nodejsVersion == "" && nodejsVersionfromFile == "" { versionSpecified = false - fromFile = ".nvmrc" + nodejsVersionfromFile = ".nvmrc" } - if fromFile != "" { - fromFile, err = filepath.Abs(fromFile) + if nodejsVersionfromFile != "" { + nodejsVersionfromFile, err = filepath.Abs(nodejsVersionfromFile) if err != nil { return } - content, err := ioutil.ReadFile(fromFile) + content, err := ioutil.ReadFile(nodejsVersionfromFile) if err != nil { if !versionSpecified { return errors.New("No version specified and could not find any version file in the current directory") @@ -120,15 +120,15 @@ func prepareFlags() (err error) { return err } - version = strings.Trim(string(content), " \n\r") + nodejsVersion = strings.Trim(string(content), " \n\r") } return } func init() { - downloadCommand.Flags().StringVarP(&version, "version", "v", "", "Which version to install") - downloadCommand.Flags().StringVarP(&fromFile, "from-file", "r", "", "Reads the version to be installed from a file. Either specify the filename or if empty it will try to read from .nvmrc file.") - downloadCommand.MarkFlagFilename("from-file") - rootCmd.AddCommand(downloadCommand) + nodejsCommand.Flags().StringVarP(&nodejsVersion, "version", "v", "", "Which version to install") + nodejsCommand.Flags().StringVarP(&nodejsVersionfromFile, "from-file", "r", "", "Reads the version to be installed from a file. Either specify the filename or if empty it will try to read from .nvmrc file.") + nodejsCommand.MarkFlagFilename("from-file") + rootCmd.AddCommand(nodejsCommand) } diff --git a/nsd/cmd/yarn.go b/nsd/cmd/yarn.go new file mode 100644 index 0000000..653067c --- /dev/null +++ b/nsd/cmd/yarn.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "errors" + "fmt" + "os" + + "github.com/mholt/archiver/v3" + Checksum "github.com/researchgate/nodejs-simple-downloader/nsd/checksum" + Download "github.com/researchgate/nodejs-simple-downloader/nsd/download" + + "github.com/spf13/cobra" +) + +var ( + yarnVersion string + yarnCommand = &cobra.Command{ + Use: "yarn [path]", + Short: "Download yarn to specific folder", + Long: "", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("requires a path argument") + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + downloadPath := args[0] + + // https://github.com/yarnpkg/yarn/releases/download/v'.$version.'/yarn-v'.$version.'.tar.gz + + err = prepareYarnFlags() + if err != nil { + return + } + + yarnURL := fmt.Sprintf("https://github.com/yarnpkg/yarn/releases/download/v%s/yarn-v%s.tar.gz", yarnVersion, yarnVersion) + yarnFilePath, err := Download.File(yarnURL) + if err != nil { + return + } + defer os.Remove(yarnFilePath) + + signatureURL := yarnURL + ".asc" + signatureFilePath, err := Download.File(signatureURL) + if err != nil { + return + } + defer os.Remove(signatureFilePath) + + keyURL := "https://dl.yarnpkg.com/debian/pubkey.gpg" + keyFilePath, err := Download.File(keyURL) + if err != nil { + return + } + defer os.Remove(keyFilePath) + + err = Checksum.VerifyGPG(signatureFilePath, keyFilePath, yarnFilePath) + if err != nil { + return + } + + err = os.RemoveAll(downloadPath) + if err != nil { + return + } + + tar := archiver.NewTarGz() + tar.StripComponents = 1 + err = tar.Unarchive(yarnFilePath, downloadPath) + + if err != nil { + return + } + + return + }, + } +) + +func prepareYarnFlags() (err error) { + if yarnVersion == "" { + return errors.New("No version specified") + } + + return +} + +func init() { + yarnCommand.Flags().StringVarP(&yarnVersion, "version", "v", "", "Which version to install") + rootCmd.AddCommand(yarnCommand) +}