diff --git a/.gitignore b/.gitignore index 66fd13c903cac02eb9657cd53fb227823484401d..5daf1d4bf8d01033ec6e3a45b09282a8b9d9bb63 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,8 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# Apps & Certs +*.ipa +*.apk +*.pem diff --git a/README.md b/README.md index fe92e0209bf9e49b36de138228210963138fe934..7903ceca5d3436fc0d93f0e49a469dffb0c3b871 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # go-ipa Simple tool to enable OTA distribution of IPA/APK to mobile devices + + +mention mkcert diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..3a75a71c318a48f34c8a143fd86c6ddb92e51af1 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,101 @@ +package cmd + +import ( + "fmt" + "log" + "net/http" + "os" + "path" + "text/template" + + "github.com/ehedenst/go-ipa/constant" + "github.com/joho/godotenv" + "github.com/phinexdaz/ipapk" + "github.com/skip2/go-qrcode" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type AppInfoWithURL struct { + *ipapk.AppInfo + URL string +} + +var scheme string +var file string +var filePath string +var appInfo *ipapk.AppInfo +var manifestTemplate *template.Template + +func qrcodeHandler(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Content-Type", "image/png") + url := fmt.Sprintf("itms-services://?action=download-manifest&url=%s://%s/manifest.plist", scheme, req.Host) + image, _ := qrcode.Encode(url, qrcode.Medium, 256) + w.Write(image) +} + +func manifestHandler(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Content-Type", "text/xml") + appInfoWithURL := AppInfoWithURL{ + AppInfo: appInfo, + URL: fmt.Sprintf("%s://%s%s", scheme, req.Host, filePath), + } + manifestTemplate.Execute(w, appInfoWithURL) +} + +func fileDownloadHandler(w http.ResponseWriter, req *http.Request) { + http.ServeFile(w, req, file) +} + +var rootCmd = &cobra.Command{ + Use: "go-ipa", + Short: "Root Short", + Long: `Root Long`, + Run: func(cmd *cobra.Command, args []string) { + var err error + appInfo, err = ipapk.NewAppParser(file) + filePath = fmt.Sprintf("/%s", path.Base(file)) + http.HandleFunc("/qrcode.png", qrcodeHandler) + http.HandleFunc("/manifest.plist", manifestHandler) + http.HandleFunc(filePath, fileDownloadHandler) + addr := viper.GetString("ADDR") + certFile := viper.GetString("CERT") + if certFile != "" { + scheme = "https" + keyFile := viper.GetString("KEY") + err = http.ListenAndServeTLS(addr, certFile, keyFile, nil) + } else { + scheme = "http" + err = http.ListenAndServe(addr, nil) + } + if err != nil { + log.Fatal("ListenAndServe: ", err) + } + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} + +func init() { + cobra.OnInitialize(initEnv) + rootCmd.PersistentFlags().StringP("addr", "a", ":9313", "addr") + rootCmd.PersistentFlags().StringP("cert", "c", "", "cert") + rootCmd.PersistentFlags().StringP("key", "k", "", "key") + rootCmd.Flags().StringVarP(&file, "file", "f", "", "file (required)") + rootCmd.MarkFlagRequired("file") + viper.SetEnvPrefix("IPA") + viper.BindPFlag("ADDR", rootCmd.PersistentFlags().Lookup("addr")) + viper.BindPFlag("CERT", rootCmd.PersistentFlags().Lookup("cert")) + viper.BindPFlag("KEY", rootCmd.PersistentFlags().Lookup("key")) + manifestTemplate, _ = template.New("manifest").Parse(constant.ManifestTemplate) +} + +func initEnv() { + _ = godotenv.Load(".env") + viper.AutomaticEnv() +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000000000000000000000000000000000000..0e2ccae366faa6e595e0275917bcb8c2f1c49b34 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,21 @@ +package cmd + +import ( + "fmt" + + "github.com/ehedenst/go-ipa/constant" + "github.com/spf13/cobra" +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "version Short", + Long: `version Long`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Version: %s\n", constant.Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/constant/templates.go b/constant/templates.go new file mode 100644 index 0000000000000000000000000000000000000000..ea51f0f84ea8b382d24e4788c45f8cbd8cc784c7 --- /dev/null +++ b/constant/templates.go @@ -0,0 +1,33 @@ +package constant + +var ManifestTemplate = `<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>items</key> + <array> + <dict> + <key>assets</key> + <array> + <dict> + <key>kind</key> + <string>software-package</string> + <key>url</key> + <string>{{.URL}}</string> + </dict> + </array> + <key>metadata</key> + <dict> + <key>bundle-identifier</key> + <string>{{.BundleId}}</string> + <key>bundle-version</key> + <string>{{.Version}}</string> + <key>kind</key> + <string>software</string> + <key>title</key> + <string>{{.Name}}</string> + </dict> + </dict> + </array> + </dict> +</plist>` diff --git a/constant/version.go b/constant/version.go new file mode 100644 index 0000000000000000000000000000000000000000..958cb7b7222dd9803006dec3344f7ef7ec301671 --- /dev/null +++ b/constant/version.go @@ -0,0 +1,6 @@ +//go:generate sh -c "sed -i \"s/const Version = \\\".*\\\"/const Version = \\\"`git describe --tags --long`\\\"/\" version.go" + +package constant + +// Version git version number +const Version = "0.0.0" diff --git a/main.go b/main.go new file mode 100644 index 0000000000000000000000000000000000000000..0320a9c97f37e17e2beb6dbcd4d38a14a4217959 --- /dev/null +++ b/main.go @@ -0,0 +1,27 @@ +// Copyright © 2016 Erik Hedenström <erik@hedenstroem.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import "github.com/ehedenst/go-ipa/cmd" + +func main() { + cmd.Execute() +}