package main import ( "flag" "fmt" "log" "net/http" "os" "path/filepath" "time" ) func main() { root := flag.String("root", "/srv/basin", "data directory holding basin.db and repos/") flag.Usage = func() { fmt.Fprintln(os.Stderr, `usage: basin [-root dir] command serve [-listen addr] [-host name] [-open] [-ssh-user name] run the web server keys user home type key sshd AuthorizedKeysCommand shell user forced command for ssh git access invite print a single use registration code user name create a user, password read from stdin`) } flag.Parse() args := flag.Args() if len(args) == 0 { flag.Usage() os.Exit(2) } switch args[0] { case "serve": serve(*root, args[1:]) case "keys": binary, _ := os.Executable() os.Exit(keys(*root, binary, args[1:])) case "shell": if len(args) != 2 { os.Exit(2) } os.Exit(shell(*root, args[1])) case "invite": store := mustStore(*root) code, err := store.CreateInvite() if err != nil { log.Fatal(err) } fmt.Println(code) case "user": if len(args) != 2 { os.Exit(2) } store := mustStore(*root) var password string fmt.Fscanln(os.Stdin, &password) if _, err := store.CreateUser(args[1], password); err != nil { log.Fatal(err) } default: flag.Usage() os.Exit(2) } } func mustStore(root string) *Store { if err := os.MkdirAll(filepath.Join(root, "repos"), 0o755); err != nil { log.Fatal(err) } store, err := openStore(filepath.Join(root, "basin.db"), false) if err != nil { log.Fatal(err) } return store } func serve(root string, args []string) { fs := flag.NewFlagSet("serve", flag.ExitOnError) listen := fs.String("listen", "127.0.0.1:3200", "address to listen on") host := fs.String("host", "localhost", "public hostname used in clone urls") open := fs.Bool("open", false, "allow registration without an invite") sshUser := fs.String("ssh-user", "git", "unix user that serves git over ssh, shown in clone urls") fs.Parse(args) store := mustStore(root) srv := &http.Server{ Addr: *listen, Handler: newServer(store, root, *host, *open, *sshUser).handler(), ReadHeaderTimeout: 10 * time.Second, } log.Printf("basin listening on %s for %s", *listen, *host) log.Fatal(srv.ListenAndServe()) }