1 package main
2
3 import (
4 "errors"
5 "flag"
6 "fmt"
7 "io"
8 "log"
9 "net/url"
10 "os"
11 "os/exec"
12 "path"
13 "path/filepath"
14 "runtime"
15
16 "codeberg.org/tslocum/gmitohtml/pkg/gmitohtml"
17 "gopkg.in/yaml.v2"
18 )
19
20 func defaultConfigPath() (string, error) {
21 homedir, err := os.UserHomeDir()
22 if err != nil {
23 return "", err
24 } else if homedir == "" {
25 return "", errors.New("a blank path to user homedir was returned")
26 }
27
28 dir := path.Join(homedir, ".config", "gmitohtml")
29 _, err = os.Stat(path.Join(dir, "config.yaml"))
30 if err == nil {
31 return path.Join(dir, "config.yaml"), nil
32 }
33
34 _, err = os.Stat(path.Join(dir, "config.yml"))
35 if err == nil {
36 return path.Join(dir, "config.yml"), nil
37 }
38
39 return path.Join(dir, "config.yaml"), nil
40 }
41
42 func serializeConfig(path string) error {
43 if path == "" {
44 return errors.New("failed to serialize: no path specified")
45
46 }
47
48 out, err := yaml.Marshal(gmitohtml.Config)
49 if err != nil {
50 return fmt.Errorf("failed to marshal configuration: %s", err)
51 }
52
53 os.MkdirAll(filepath.Dir(path), 0755)
54 err = os.WriteFile(path, out, 0644)
55 if err != nil {
56 return fmt.Errorf("failed to write to %s: %s", path, err)
57 }
58
59 return nil
60 }
61
62 func deserializeConfig(path string) error {
63 if path == "" {
64 return errors.New("failed to deserialize: no path specified")
65 }
66
67 _, err := os.Stat(path)
68 if os.IsNotExist(err) {
69 return nil
70 }
71
72 configData, err := os.ReadFile(path)
73 if err != nil {
74 return fmt.Errorf("failed to read file: %s", err)
75 }
76
77 err = yaml.Unmarshal(configData, gmitohtml.Config)
78 if err != nil {
79 return fmt.Errorf("failed to parse file: %s", err)
80 }
81
82 return nil
83 }
84
85 func openBrowser(url string) {
86 var err error
87 switch runtime.GOOS {
88 case "linux":
89 err = exec.Command("xdg-open", url).Start()
90 case "windows":
91 err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
92 case "darwin":
93 err = exec.Command("open", url).Start()
94 default:
95 err = fmt.Errorf("unsupported platform")
96 }
97 if err != nil {
98 log.Fatal(err)
99 }
100 }
101
102 func main() {
103 var (
104 view bool
105 allowFile bool
106 daemon string
107 hostname string
108 configFile string
109 )
110 flag.BoolVar(&view, "view", false, "open web browser")
111 flag.BoolVar(&allowFile, "allow-file", false, "allow local file access via file://")
112 flag.StringVar(&daemon, "daemon", "", "start daemon on specified address")
113 flag.StringVar(&hostname, "hostname", "", "server hostname (e.g. rocket9labs.com) (defaults to daemon address)")
114 flag.StringVar(&configFile, "config", "", "path to configuration file")
115
116 flag.Parse()
117
118 defaultConfig, err := defaultConfigPath()
119 if err != nil {
120 log.Fatal(err)
121 } else if configFile == "" {
122 configFile = defaultConfig
123 }
124
125 if configFile != "" {
126 var configExists bool
127 if _, err := os.Stat(defaultConfig); !os.IsNotExist(err) {
128 configExists = true
129 }
130
131 if configExists || configFile != defaultConfig {
132 err := deserializeConfig(configFile)
133 if err != nil {
134 log.Fatalf("failed to read configuration file at %s: %v\nSee CONFIGURATION.md for information on configuring gmitohtml", configFile, err)
135 }
136
137 for u, label := range gmitohtml.Config.Bookmarks {
138 gmitohtml.AddBookmark(u, label)
139 }
140 }
141 }
142
143 for domain, cc := range gmitohtml.Config.Certs {
144 certData, err := os.ReadFile(cc.Cert)
145 if err != nil {
146 log.Fatalf("failed to load client certificate for domain %s: %s", domain, err)
147 }
148
149 keyData, err := os.ReadFile(cc.Key)
150 if err != nil {
151 log.Fatalf("failed to load client certificate for domain %s: %s", domain, err)
152 }
153
154 err = gmitohtml.SetClientCertificate(domain, certData, keyData)
155 if err != nil {
156 log.Fatalf("failed to load client certificate for domain %s", domain)
157 }
158 }
159
160 if daemon != "" {
161 gmitohtml.SetOnBookmarksChanged(func() {
162 gmitohtml.Config.Bookmarks = gmitohtml.GetBookmarks()
163
164 err := serializeConfig(configFile)
165 if err != nil {
166 log.Fatal(err)
167 }
168 })
169
170 err := gmitohtml.StartDaemon(daemon, hostname, allowFile)
171 if err != nil {
172 log.Fatal(err)
173 }
174
175 if view {
176 openBrowser("http://" + daemon)
177 }
178
179 select {}
180 }
181
182 data, err := io.ReadAll(os.Stdin)
183 if err != nil {
184 log.Fatal(err)
185 }
186
187 data = gmitohtml.Convert(data, "")
188
189 if view {
190 openBrowser(string(append([]byte("data:text/html,"), []byte(url.PathEscape(string(data)))...)))
191 return
192 }
193 fmt.Print(gmitohtml.Convert(data, ""))
194 }
195
View as plain text