func main() { banner := fmt.Sprintf("%s is a tool for managing 1Password vaults.", os.Args[0]) parser := cmdmodes.NewParser(commandModes) agentFlag := flag.Bool("agent", false, "Start 1pass in agent mode") vaultPathFlag := flag.String("vault", "", "Custom vault path") lowSecFlag := flag.Bool("low-security", false, "Use lower security but faster encryption for the master password") flag.Usage = func() { parser.PrintHelp(banner, "") } flag.Parse() if *agentFlag { agent := NewAgent() err := agent.Serve() if err != nil { fatalErr(err, "") } return } config := readConfig() if *vaultPathFlag != "" { config.VaultDir = *vaultPathFlag } if len(flag.Args()) < 1 || flag.Args()[0] == "help" { command := "" if len(flag.Args()) > 1 { command = flag.Args()[1] } parser.PrintHelp(banner, command) os.Exit(1) } mode := flag.Args()[0] cmdArgs := flag.Args()[1:] // handle commands which do not require // an existing vault handled := true switch mode { case "new": var path string if *vaultPathFlag != "" { path = *vaultPathFlag } else { _ = parser.ParseCmdArgs(mode, cmdArgs, &path) if len(path) == 0 { path = os.Getenv("HOME") + "/Dropbox/1Password/1Password.agilekeychain" } } createNewVault(path, *lowSecFlag) case "gen-password": fmt.Printf("%s\n", genDefaultPassword()) case "set-vault": var newPath string _ = parser.ParseCmdArgs(mode, cmdArgs, &newPath) config.VaultDir = newPath writeConfig(&config) default: handled = false } if handled { return } // handle commands which require a connected but not // unlocked vault if config.VaultDir == "" { initVaultConfig(&config) } vault, err := onepass.OpenVault(config.VaultDir) if err != nil { fatalErr(err, "Unable to setup vault") } if mode == "info" { fmt.Printf("Vault path: %s\n", config.VaultDir) return } // remaining commands require an unlocked vault // connect to the 1pass agent daemon. Start it automatically // if not already running or the agent/client version do not // match agentClient, err := DialAgent(config.VaultDir) if err == nil && agentClient.Info.BinaryVersion != appBinaryVersion() { if agentClient.Info.Pid != 0 { fmt.Fprintf(os.Stderr, "Agent/client version mismatch. Restarting agent.\n") // kill the existing agent err = syscall.Kill(agentClient.Info.Pid, syscall.SIGINT) if err != nil { fatalErr(err, "Failed to shut down existing agent") } agentClient = OnePassAgentClient{} } } if agentClient.Info.Pid == 0 { err = startAgent() if err != nil { fatalErr(err, "Unable to start 1pass keychain agent") } maxWait := time.Now().Add(1 * time.Second) for time.Now().Before(maxWait) { agentClient, err = DialAgent(config.VaultDir) if err == nil { break } else { fmt.Errorf("Error starting agent: %v\n", err) } time.Sleep(10 * time.Millisecond) } if err != nil { fatalErr(err, "Unable to connect to 1pass keychain agent") } } if mode == "lock" { err = agentClient.Lock() if err != nil { fatalErr(err, "Failed to lock keychain") } return } if mode == "set-password" { fmt.Printf("Current master password: "******"Failed to check lock status") } if locked { fmt.Printf("Master password: "******"Unable to read password hint: %v\n", err) } fmt.Fprintf(os.Stderr, "Incorrect password (hint: %s)\n", hint) os.Exit(1) } else { fatalErr(err, "Unable to unlock vault") } } } err = agentClient.RefreshAccess() if err != nil { fatalErr(err, "Unable to refresh vault access") } vault.CryptoAgent = &agentClient handleVaultCmd(&vault, mode, cmdArgs) }
func handleVaultCmd(vault *onepass.Vault, mode string, cmdArgs []string) { parser := cmdmodes.NewParser(commandModes) var err error switch mode { case "list": var pattern string parser.ParseCmdArgs(mode, cmdArgs, &pattern) listMatchingItems(vault, pattern) case "list-folder": var pattern string parser.ParseCmdArgs(mode, cmdArgs, &pattern) listFolder(vault, pattern) case "show-json": fallthrough case "show": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } showItems(vault, pattern, mode == "show-json") case "add": var itemType string var title string err = parser.ParseCmdArgs(mode, cmdArgs, &itemType, &title) if err != nil { fatalErr(err, "") } addItem(vault, title, itemType) case "edit": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } editItem(vault, pattern) case "remove": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } removeItems(vault, pattern) case "trash": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } trashItems(vault, pattern) case "restore": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } restoreItems(vault, pattern) case "rename": var pattern string var newTitle string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern, &newTitle) if err != nil { fatalErr(err, "") } renameItem(vault, pattern, newTitle) case "copy": var pattern string var field string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern, &field) if err != nil { fatalErr(err, "") } copyToClipboard(vault, pattern, field) case "import": var path string err = parser.ParseCmdArgs(mode, cmdArgs, &path) if err != nil { fatalErr(err, "") } importItems(vault, path) case "export": var pattern string var path string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern, &path) if err != nil { fatalErr(err, "") } exportItems(vault, pattern, path) case "export-item-templates": var pattern string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern) if err != nil { fatalErr(err, "") } exportItemTemplates(vault, pattern) case "move": var folderPattern string var itemPattern string err = parser.ParseCmdArgs(mode, cmdArgs, &itemPattern, &folderPattern) if err != nil { fatalErr(err, "") } moveItemsToFolder(vault, itemPattern, folderPattern) case "list-tag": var tag string err = parser.ParseCmdArgs(mode, cmdArgs, &tag) if err != nil { fatalErr(err, "") } listTag(vault, tag) case "list-tags": listTags(vault) case "add-tag": var pattern string var tag string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern, &tag) if err != nil { fatalErr(err, "") } addTag(vault, pattern, tag) case "remove-tag": var pattern string var tag string err = parser.ParseCmdArgs(mode, cmdArgs, &pattern, &tag) if err != nil { fatalErr(err, "") } removeTag(vault, pattern, tag) default: fmt.Fprintf(os.Stderr, "Unknown command: %s\n", mode) os.Exit(1) } }