// The rsagen command generates rsa.PublicKey variables from PEM-encoded // RSA public keys. package main import ( "bufio" "bytes" "crypto/rsa" "embed" "flag" "fmt" "go/format" "io" "io/fs" "log" "os" "text/template" "github.com/go-faster/errors" "go.mau.fi/mautrix-telegram/pkg/gotd/crypto" ) //go:embed _template/*.tmpl var embedFS embed.FS var funcs = template.FuncMap{ "fingerprint": func(pubkey *rsa.PublicKey) string { return fmt.Sprintf("%08x", uint64(crypto.RSAFingerprint(pubkey))) }, "chunks": func(b []byte, size int) [][]byte { var chunks [][]byte for len(b) > size { chunks = append(chunks, b[:size]) b = b[size:] } if len(b) != 0 { chunks = append(chunks, b) } return chunks }, "single": func(keys []*rsa.PublicKey) (*rsa.PublicKey, error) { if count := len(keys); count != 1 { return nil, errors.Errorf("expected single key, got %d keys", count) } return keys[0], nil }, } func main() { if err := run(); err != nil { os.Exit(1) } } func run() error { log.SetFlags(log.Llongfile) var ( inPath = flag.String("f", "", "input path (defaults to stdin)") outPath = flag.String("o", "", "output path (defaults to stdout)") tplPath = flag.String("templates", "", "templates directory (defaults to embed)") tplName = flag.String("exec", "main.tmpl", "template name") pkgName = flag.String("pkg", "main", "package name") varName = flag.String("var", "PK", "variable name") singleMode = flag.Bool("single", false, "emit single key instead of slice") formatOutput = flag.Bool("format", true, "run gofmt on output") testFunc = flag.String("test", "", "test function name") ) flag.Parse() if *testFunc == "" { *testFunc = "TestFingerprint" + *varName } var err error var in []byte if *inPath != "" { in, err = os.ReadFile(*inPath) } else { in, err = io.ReadAll(os.Stdin) } if err != nil { log.Printf("read input: %v", err) return err } keys, err := crypto.ParseRSAPublicKeys(in) if err != nil { log.Printf("parse public keys: %v", err) return err } fsys, _ := fs.Sub(embedFS, "_template") if *tplPath != "" { fsys = os.DirFS(*tplPath) } tpl, err := template.New("").Funcs(funcs).ParseFS(fsys, "*.tmpl") if err != nil { log.Printf("parse templates: %v", err) return err } var inLines [][]byte for sc := bufio.NewScanner(bytes.NewReader(in)); sc.Scan(); { line := sc.Bytes() line = bytes.TrimSpace(line) if len(line) == 0 { continue } inLines = append(inLines, line) } buf := bytes.NewBuffer(nil) if err := tpl.ExecuteTemplate(buf, *tplName, map[string]interface{}{ "Package": *pkgName, "Variable": *varName, "Keys": keys, "Single": *singleMode, "InputLines": inLines, "TestFunc": *testFunc, }); err != nil { log.Printf("execute template: %v", err) return err } if *formatOutput { p, err := format.Source(buf.Bytes()) if err != nil { log.Printf("format output: %v", err) return err } buf = bytes.NewBuffer(p) } if *outPath != "" { err = os.WriteFile(*outPath, buf.Bytes(), 0o600) } else { _, err = buf.WriteTo(os.Stdout) } if err != nil { log.Printf("write output: %v", err) return err } return nil }