package main import ( _ "embed" "fmt" "os" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" "github.com/studiokaiji/nostr-webhost/cmd/deploy" "github.com/studiokaiji/nostr-webhost/cmd/keystore" "github.com/studiokaiji/nostr-webhost/cmd/relays" "github.com/studiokaiji/nostr-webhost/cmd/server" "github.com/urfave/cli/v2" ) //go:embed cute-ostrich.txt var cuteOstrich string func main() { app := &cli.App{ Commands: []*cli.Command{ { Name: "deploy", Usage: "๐ŸŒ Deploy nostr website", Flags: []cli.Flag{ &cli.StringFlag{ Name: "path", Aliases: []string{"p"}, Value: "./", Usage: "Site directory", }, &cli.BoolFlag{ Name: "replaceable", Aliases: []string{"r"}, Usage: "Specify 'true' explicitly when using NIP-33", Value: true, }, &cli.StringFlag{ Name: "identifier", Aliases: []string{"d"}, Usage: "index.html identifier (valid only if replaceable option is true)", }, }, Action: func(ctx *cli.Context) error { fmt.Println("๐ŸŒ Deploying...") path := ctx.String("path") replaceable := ctx.Bool("replaceable") dTag := ctx.String("identifier") _, encoded, dTag, err := deploy.Deploy(path, replaceable, dTag) if err == nil { fmt.Println("๐ŸŒ Deploy Complete!") pubkey, err := keystore.GetPublic() if err != nil { os.Exit(1) } npub, err := nip19.EncodePublicKey(pubkey) if err != nil { os.Exit(1) } defaultModeUrl := "https://h.hostr.cc" secureModeUrl := fmt.Sprintf("https://%s.h.hostr.cc", npub) if replaceable { defaultModeUrl = fmt.Sprintf("%s/p/%s/d/%s", defaultModeUrl, npub, dTag) secureModeUrl = fmt.Sprintf("%s/d/%s", secureModeUrl, dTag) } else { defaultModeUrl = fmt.Sprintf("%s/e/%s", defaultModeUrl, encoded) secureModeUrl = fmt.Sprintf("%s/e/%s", secureModeUrl, encoded) } fmt.Println("\n\033[1m========= ๐Ÿšต Access To =========\033") fmt.Printf("\n\033[1m๐Ÿ—ƒ๏ธ Default Mode:\033[0m\n\x1b[36m%s\x1b[0m\n", defaultModeUrl) fmt.Printf("\033[1m\n๐Ÿ”‘ Secure Mode:\033[0m\n\x1b[36m%s\x1b[0m\n", secureModeUrl) fmt.Printf("\n\x1b[90mh.hostr.cc is just one endpoint, so depending on the relay configuration, it may not be accessible.\x1b[0m\n") fmt.Printf("\n\033[1m=================================\033\n") } return err }, }, { Name: "add-relay", Usage: "๐Ÿ“Œ Add nostr relay", Action: func(ctx *cli.Context) error { args := ctx.Args() relay := args.Get(args.Len() - 1) err := relays.AddRelay(relay) if err == nil { fmt.Println("๐Ÿ“Œ Added relay:", relay) } return err }, }, { Name: "remove-relay", Usage: "๐Ÿ—‘ Remove nostr relay", Action: func(ctx *cli.Context) error { args := ctx.Args() relay := args.Get(args.Len() - 1) err := relays.RemoveRelay(relay) if err == nil { fmt.Println("๐Ÿ—‘ Removed relay:", relay) } return err }, }, { Name: "list-relays", Usage: "๐Ÿ“ List added nostr relays", Action: func(ctx *cli.Context) error { relays, err := relays.GetAllRelays() fmt.Println("===========================") for _, relay := range relays { fmt.Println(relay) } fmt.Println("===========================") return err }, }, { Name: "set-private", Usage: "๐Ÿ” Set private key", Action: func(ctx *cli.Context) error { args := ctx.Args() key := args.Get(args.Len() - 1) err := keystore.SetSecret(key) if err == nil { fmt.Println("๐Ÿ” Secret is recorded") } return err }, }, { Name: "show-public", Usage: "๐Ÿ“› Show public key", Action: func(ctx *cli.Context) error { _, _, err := keystore.ShowPublic() return err }, }, { Name: "generate-key", Usage: "๐Ÿ— Generate key", Action: func(ctx *cli.Context) error { key := nostr.GeneratePrivateKey() err := keystore.SetSecret(key) if err == nil { fmt.Print("๐Ÿ— Generated key\n๐Ÿ— You can check the public key with 'hostr show-public'\n") } return err }, }, { Name: "start", Usage: "๐Ÿ•บ Wake up web server", Flags: []cli.Flag{ &cli.StringFlag{ Name: "port", Aliases: []string{"p"}, Value: "3000", Usage: "Web server port", }, &cli.StringFlag{ Name: "mode", Aliases: []string{"m"}, Value: "normal", Usage: "๐Ÿงช Experimental: Enabled subdomain-based access in replaceable events.", Action: func(ctx *cli.Context, v string) error { if v != "normal" && v != "hybrid" && v != "secure" { return fmt.Errorf("Invalid mode flag. Must be 'normal', 'hybrid', or 'secure'.") } return nil }, }, }, Action: func(ctx *cli.Context) error { port := ctx.String("port") mode := ctx.String("mode") server.Start(port, mode) return nil }, }, }, } if len(os.Args) < 2 || os.Args[1] == "help" || os.Args[1] == "h" { // Display ostrich fmt.Println(cuteOstrich) } // Start app err := app.Run(os.Args) if err != nil { fmt.Println(err) } }