io.stallion.secrets.SecretsCommandLineManager.java Source code

Java tutorial

Introduction

Here is the source code for io.stallion.secrets.SecretsCommandLineManager.java

Source

/*
 * Stallion Core: A Modern Web Framework
 *
 * Copyright (C) 2015 - 2016 Stallion Software LLC.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 2 of
 * the License, or (at your option) any later version. This program is distributed in the hope that
 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details. You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
 *
 *
 *
 */

package io.stallion.secrets;

import io.stallion.boot.CommandOptionsBase;
import io.stallion.services.Log;
import io.stallion.settings.childSections.SecretsSettings;
import io.stallion.utils.Prompter;
import net.east301.keyring.BackendNotSupportedException;
import net.east301.keyring.Keyring;
import net.east301.keyring.PasswordRetrievalException;
import net.east301.keyring.PasswordSaveException;
import net.east301.keyring.util.LockException;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;

import static io.stallion.utils.Literals.*;

public class SecretsCommandLineManager {

    private String password = "";
    private SecretsVault vault;
    private String targetFolder = "";
    private boolean keyringAccesible = false;
    private boolean inKeyChain = false;
    private String keyringServiceName = "";
    private static final String keyringAccountName = "stallion";

    private static final String lock = "            .-\"\"-.\n" + "           / .--. \\\n"
            + "          / /    \\ \\\n" + "          | |    | |\n" + "          | |.-\"\"-.|\n"
            + "         ///`.::::.`\\\n" + "        ||| ::/  \\:: ;\n" + "        ||; ::\\__/:: ;\n"
            + "         \\\\\\ '::::' /\n" + "          `=':-..-'`";

    public SecretsVault loadVault(String appPath, SecretsSettings secretsSettings) {
        return loadVault(appPath, secretsSettings, "");
    }

    public SecretsVault loadVault(String appPath, SecretsSettings secretsSettings, String password) {

        targetFolder = appPath;
        keyringServiceName = "Stallion Secrets Key: " + targetFolder;

        if (secretsSettings == null) {
            Log.info("secretsSettings is null");
        } else {
            Log.info("Secrets passphrase file is {0}", secretsSettings.getPassPhraseFile());
        }

        if (empty(password)) {
            password = findPasswordFromEnv();
        }
        if (empty(password)) {
            password = findPasswordFromFile(secretsSettings);
        }

        if (empty(password)) {
            password = findPasswordInKeyring();
        }

        if (empty(password)) {
            password = new Prompter(
                    "What is your encryption password? If you are creating a secrets file for the first time,"
                            + "generate a new random string of at least 16 alpha-numeric characters, save it somewhere safe "
                            + "(like your password manager), and then paste it in here. This password is not recoverable. If you lost it, "
                            + "your secrets file will be locked forever.\nEnter your encryption password: ") {
                @Override
                public boolean validate(String line) {
                    if (line.length() < 15) {
                        this.lastErrorMessage = "Your password must be at least 20 characters.";
                        return false;
                    }
                    return true;
                }
            }.prompt();
        }

        vault = new SecretsVault(targetFolder, password);

        promptStorePassword(password);
        return vault;
    }

    public void start(CommandOptionsBase options) {
        System.out.print("\n\n" + lock + "\n\n");
        System.out.println(
                "Welcome to the Stallion Secrets Manager.\n\n You can view your secrets, create new secrets, change secrets, delete secrets");

        targetFolder = options.getTargetPath();
        loadVault(options.getTargetPath(), null);

        while (true) {
            String line = new Prompter("What do you want to do? Options: new/edit/delete/list/quit ")
                    .setChoices("new", "edit", "delete", "list", "quit").prompt();
            switch (line) {
            case "quit":
                return;
            case "new":
                newSecret();
                break;
            case "delete":
                deleteSecrets();
                break;
            case "list":
                listSecrets();
                break;
            case "edit":
                editSecret();
                break;
            default:
                continue;
            }
        }

    }

    public String findPasswordFromEnv() {
        return System.getenv("STALLION_SECRETS_PASSPHRASE");
    }

    public String findPasswordFromFile(SecretsSettings secretsSettings) {
        if (secretsSettings == null) {
            return "";
        }
        String path = or(secretsSettings.getPassPhraseFile(), "/usr/local/etc/stallion-secrets-passphrase");
        Log.info("Looking for secrets pass phrase in file {0}", path);
        File passPhraseFile = new File(path);

        if (!passPhraseFile.exists()) {
            return "";
        }
        try {
            return FileUtils.readFileToString(passPhraseFile, UTF8).trim();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String findPasswordInKeyring() {

        Keyring keyring;
        try {
            keyring = Keyring.create();
        } catch (BackendNotSupportedException ex) {
            Log.info("Backend not supported for storing passphrase in Keyring");
            return "";
        }

        keyringAccesible = true;

        // some backend directory handles a file to store password to disks.
        // in this case, we must set path to password store file by Keyring.setKeyStorePath
        // before using Keyring.getPassword and Keyring.getPassword.
        if (keyring.isKeyStorePathRequired()) {
            try {
                File keyStoreFile = File.createTempFile("keystore", ".keystore");
                keyring.setKeyStorePath(keyStoreFile.getPath());
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }

        //
        // Retrieve password from password store
        //

        // Password can be retrieved by using Keyring.getPassword method.
        // PasswordRetrievalException is thrown when some error happened while getting password.
        // LockException is thrown when keyring backend failed to lock password store file.
        try {
            String password = keyring.getPassword(keyringServiceName, keyringAccountName);
            if (!empty(password)) {
                inKeyChain = true;
            }
            return password;
        } catch (LockException ex) {
            throw new RuntimeException(ex);
        } catch (PasswordRetrievalException ex) {
            Log.info("Could not retrieve passphrase from the keychain");
            return "";
        }
    }

    public void promptStorePassword(String password) {
        if (!keyringAccesible) {
            return;
        }
        if (inKeyChain) {
            return;
        }
        boolean shouldStore = new Prompter("Store this passphrase in your local keychain? (Y/n) ").yesNo();
        if (!shouldStore) {
            Log.info("Not should store!");
            return;
        }

        Keyring keyring;
        try {
            keyring = Keyring.create();
        } catch (BackendNotSupportedException ex) {
            Log.info("Backend not supported for storing passphrase in Keyring");
            return;
        }

        // some backend directory handles a file to store password to disks.
        // in this case, we must set path to password store file by Keyring.setKeyStorePath
        // before using Keyring.getPassword and Keyring.getPassword.
        if (keyring.isKeyStorePathRequired()) {
            try {
                File keyStoreFile = File.createTempFile("keystore", ".keystore");
                keyring.setKeyStorePath(keyStoreFile.getPath());
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }

        // Password can be stored to password store by using Keyring.setPassword method.
        // PasswordSaveException is thrown when some error happened while saving password.
        // LockException is thrown when keyring backend failed to lock password store file.
        try {
            keyring.setPassword(keyringServiceName, keyringAccountName, password);
        } catch (LockException ex) {
            throw new RuntimeException(ex);
        } catch (PasswordSaveException ex) {
            throw new RuntimeException(ex);
        }

    }

    public void newSecret() {
        String name = new Prompter(
                "Secret name (You will use this name in your settings file to retrieve the secret): ").prompt();
        String value = new Prompter("Secret value: ").prompt();
        vault.add(name, value);
        vault.save();
        System.out.println("Secret added.");

    }

    public void editSecret() {
        String name = new Prompter("Secret name: ").setChoices(vault.getSecretNames()).prompt();
        String value = new Prompter("Secret value: ").prompt();
        vault.update(name, value);
        vault.save();
        System.out.println("Secret updated.");

    }

    public void listSecrets() {
        MessageFormat format = new MessageFormat("{0}: {1}");
        System.out.print("\n");
        if (vault.getSecretNames().size() == 0) {
            System.out.println("No secrets defined.");
        }
        for (String name : vault.getSecretNames()) {
            System.out.println(format.format("{0}: {1}", name, vault.getSecret(name)));
        }
        System.out.print("\n");
    }

    public void deleteSecrets() {
        String name = new Prompter("Secret name: ").setChoices(vault.getSecretNames()).prompt();
        vault.getSecrets().remove(name);
        vault.save();
        System.out.println("Secret deleted.");
    }

}