From 245499196c1858bb8844d61d1b9d8888dfba9cb8 Mon Sep 17 00:00:00 2001 From: Norm MacLennan Date: Wed, 18 May 2016 08:54:47 -0400 Subject: [PATCH] rdocing things --- lib/zanzibar.rb | 36 ++++++++++++++++++++++++---------- lib/zanzibar/actions/base.rb | 6 ++++++ lib/zanzibar/actions/bundle.rb | 18 +++++++++++++++++ lib/zanzibar/actions/get.rb | 17 ++++++++++++++++ lib/zanzibar/actions/init.rb | 5 +++++ lib/zanzibar/cli.rb | 25 ++++++++++++++++++++++- lib/zanzibar/client.rb | 23 +++++++++++++++++----- lib/zanzibar/defaults.rb | 10 ++++++++++ lib/zanzibar/ui.rb | 19 ++++++++++++++++++ lib/zanzibar/version.rb | 1 + 10 files changed, 144 insertions(+), 16 deletions(-) diff --git a/lib/zanzibar.rb b/lib/zanzibar.rb index 2ecccd2..271bf8d 100644 --- a/lib/zanzibar.rb +++ b/lib/zanzibar.rb @@ -7,7 +7,7 @@ require 'zanzibar/client' module Zanzibar ## - # Class for interacting with Secret Server + # High-level operations for downloading things from Secret Server class Zanzibar ## # @param args{:domain, :wsdl, :pwd, :username, :globals{}} @@ -20,7 +20,8 @@ module Zanzibar @client = Client.new(@username, @password, @domain, @wsdl, args[:globals]) end - ## Gets the user's password if none is provided in the constructor. + ## + # Gets the user's password if none is provided in the constructor. # @return [String] the password for the current user def prompt_for_password puts "Please enter password for #{@username}:" @@ -29,21 +30,24 @@ module Zanzibar end end - ## Gets the wsdl document location if none is provided in the constructor + ## + # Gets the wsdl document location if none is provided in the constructor # @return [String] the location of the WDSL document def prompt_for_wsdl_location puts 'Enter the URL of the Secret Server WSDL:' STDIN.gets.chomp end - ## Gets the domain of the Secret Server installation if none is provided in the constructor + ## + # Gets the domain of the Secret Server installation if none is provided in the constructor # @return [String] the domain of the secret server installation def prompt_for_domain puts 'Enter the domain of your Secret Server:' STDIN.gets.chomp end - ## Retrieve the value from a field label of a secret + ## + # Retrieve the value from a field label of a secret # Will raise an error if there are any issues # @param [Integer] the secret id # @param [String] the field label to get, defaults to Password @@ -56,7 +60,8 @@ module Zanzibar raise "There was an error getting '#{fieldlabel}' for secret #{scrt_id}: #{err}" end - ## Retrieve a simple password from a secret + ## + # Retrieve a simple password from a secret # Calls get get_fieldlabel_value() # @param [Integer] the secret id # @return [String] the password for the given secret @@ -64,7 +69,8 @@ module Zanzibar get_fieldlabel_value(scrt_id) end - ## Get the password, save it to a file, and return the path to the file. + ## + # Get the password, save it to a file, and return the path to the file. def get_username_and_password_and_save(scrt_id, path, name) secret_items = @client.get_secret(scrt_id)[:secret][:items][:secret_item] password = @client.get_secret_item_by_field_name(secret_items, 'Password')[:value] @@ -73,7 +79,8 @@ module Zanzibar File.join(path, name) end - ## Write the password to a file. Intended for use with a Zanzifile + ## + # Write the password to a file. Intended for use with a Zanzifile def save_username_and_password_to_file(password, username, path, name) user_pass = { 'username' => username.to_s, 'password' => password.to_s }.to_yaml File.open(File.join(path, name), 'wb') do |file| @@ -81,7 +88,8 @@ module Zanzibar end end - ## Downloads a file for a secret and places it where Zanzibar is running, or :path if specified + ## + # Downloads a file for a secret and places it where Zanzibar is running, or :path if specified # Raise on error # @param [Hash] args, :scrt_id, :type (one of "Private Key", "Public Key", "Attachment"), :scrt_item_id - optional, :path - optional def download_secret_file(args = {}) @@ -92,17 +100,25 @@ module Zanzibar raise "There was an error getting the #{args[:type]} for secret #{args[:scrt_id]}: #{err}" end - ## Methods to maintain backwards compatibility + ## + # Download a private key secret + # @deprecated def download_private_key(args = {}) args[:type] = 'Private Key' download_secret_file(args) end + ## + # Download a public key secret + # @deprecated def download_public_key(args = {}) args[:type] = 'Public Key' download_secret_file(args) end + ## + # Download an arbitrary secret attachment + # @deprecated def download_attachment(args = {}) args[:type] = 'Attachment' download_secret_file(args) diff --git a/lib/zanzibar/actions/base.rb b/lib/zanzibar/actions/base.rb index e39fef2..7e1e936 100644 --- a/lib/zanzibar/actions/base.rb +++ b/lib/zanzibar/actions/base.rb @@ -2,12 +2,18 @@ module Zanzibar module Actions # Basic plumbing for all actions class Base + ## + # The options passed in from the Thor action attr_accessor :options private :options= + ## + # The logger that Thor is using for this run attr_accessor :logger private :logger= + ## + # Initialize the basic components used by all actions def initialize(logger, options = {}) self.logger = logger self.options = options diff --git a/lib/zanzibar/actions/bundle.rb b/lib/zanzibar/actions/bundle.rb index 816cdcd..7210dea 100644 --- a/lib/zanzibar/actions/bundle.rb +++ b/lib/zanzibar/actions/bundle.rb @@ -6,17 +6,35 @@ module Zanzibar module Actions # Download or verify the secrets in a Zanzifile class Bundle < Base + ## + # The settings defined in the Zanzifile attr_accessor :settings + + ## + # The unresolved secrets from the Zanzifile attr_accessor :remote_secrets + + ## + # The resolved secrets from the Zanzifile.resolved attr_accessor :local_secrets + + ## + # Whether to disregard local secrets and re-download regardness attr_accessor :update + + ## + # Our Zanzibar client attr_accessor :zanzibar + ## + # An action that will fetch secrets defined in a Zanzifile def initialize(ui, options, args = {}) super(ui, options) @update = args[:update] end + ## + # Coordinate downloading to secrets (or skipping ones we already have) def run ensure_zanzifile load_required_secrets diff --git a/lib/zanzibar/actions/get.rb b/lib/zanzibar/actions/get.rb index d9f3a43..cbf40bb 100644 --- a/lib/zanzibar/actions/get.rb +++ b/lib/zanzibar/actions/get.rb @@ -7,15 +7,24 @@ module Zanzibar module Actions # Fetch a single secret class Get < Base + ## + # The options to use when initializing our Zanzibar client attr_accessor :zanibar_options + + ## + # The id of the secret to download attr_accessor :scrt_id + ## + # Initialize the action def initialize(ui, options, scrt_id) super(ui, options) @scrt_id = scrt_id @zanzibar_options = {} end + ## + # Ensure we have the options we need and download the secret def run construct_options ensure_options @@ -23,6 +32,8 @@ module Zanzibar fetch_secret(@scrt_id) end + ## + # Actually download the secret def fetch_secret(scrt_id) scrt = ::Zanzibar::Zanzibar.new(@zanzibar_options) @@ -34,6 +45,8 @@ module Zanzibar end end + ## + # Coalesce our options and some defaults to ensure we are ready to run def construct_options @zanzibar_options[:wsdl] = construct_wsdl @zanzibar_options[:globals] = { ssl_verify_mode: :none } if options['ignoressl'] @@ -44,6 +57,8 @@ module Zanzibar @zanzibar_options[:filelabel] = options['filelabel'] if options['filelabel'] end + ## + # Construct a WSDL URL from the server hostname if necessary def construct_wsdl if options['wsdl'].nil? && options['server'] DEFAULT_WSDL % options['server'] @@ -52,6 +67,8 @@ module Zanzibar end end + ## + # Make sure a proper WSDL was constructed def ensure_options return if @zanzibar_options[:wsdl] raise Error, NO_WSDL_ERROR diff --git a/lib/zanzibar/actions/init.rb b/lib/zanzibar/actions/init.rb index de314d7..27a3905 100644 --- a/lib/zanzibar/actions/init.rb +++ b/lib/zanzibar/actions/init.rb @@ -8,6 +8,8 @@ module Zanzibar module Actions # Create a new Zanzifile class Init < Base + ## + # Make sure we don't already have a Zanzifile, then template one def run check_for_zanzifile write_template @@ -28,9 +30,12 @@ module Zanzibar end end + ## # Allows us to easily feed our options hash # to an ERB class TemplateRenderer < OpenStruct + ## + # Render an ERB template to a string def render(template) ERB.new(template).result(binding) end diff --git a/lib/zanzibar/cli.rb b/lib/zanzibar/cli.rb index 5550eff..16d1fcf 100644 --- a/lib/zanzibar/cli.rb +++ b/lib/zanzibar/cli.rb @@ -8,12 +8,20 @@ require 'zanzibar/error' require 'zanzibar/defaults' module Zanzibar - # The `zanzibar` binay/thor application main class + + ## + # The `zanzibar` binary/thor application main class. + # See http://whatisthor.com/ for information on syntax. + class Cli < Thor include Thor::Actions + ## + # The stream to which we are writing messages (usually stdout) attr_accessor :ui + ## + # Initialize the application and set some logging defaults def initialize(*) super the_shell = (options['no-color'] ? Thor::Shell::Basic.new : shell) @@ -24,11 +32,15 @@ module Zanzibar debug_header end + ## + # Print the version of the application desc 'version', 'Display your Zanzibar verion' def version say "#{APPLICATION_NAME} Version: #{VERSION}" end + ## + # Generate a new blank Zanzifile desc 'init', "Create an empty #{ZANZIFILE_NAME} in the current directory." option 'verbose', type: :boolean, default: false, aliases: :v option 'wsdl', type: :string, aliases: :w, @@ -46,8 +58,12 @@ module Zanzibar run_action { init! } end + ## + # Fetch secrets declared in a local Zanzifle + desc 'bundle', "Fetch secrets declared in your #{ZANZIFILE_NAME}" option 'verbose', type: :boolean, default: false, aliases: :v + def bundle run_action { bundle! } end @@ -59,8 +75,12 @@ module Zanzibar desc 'install', "Alias to `#{APPLICATION_NAME} bundle`" alias install bundle + ## + # Redownload Zazifile secrets + desc 'update', "Redownload all secrets in your #{ZANZIFILE_NAME}" option 'verbose', type: :boolean, default: false, aliases: :v + def update run_action { update! } end @@ -80,6 +100,8 @@ module Zanzibar desc: 'Specify a field (by label) to get' option 'username', type: :string, aliases: :u option 'password', type: :string, aliases: :p + ## + # Fetch a single secret specified on the commandline def get(scrt_id) run_action { get! scrt_id } end @@ -93,6 +115,7 @@ module Zanzibar @ui.debug { "#{APPLICATION_NAME} Version: #{VERSION}" } end + ## # Run the specified action and rescue errors we # explicitly send back to format them def run_action(&_block) diff --git a/lib/zanzibar/client.rb b/lib/zanzibar/client.rb index e91eb4b..044b7fb 100644 --- a/lib/zanzibar/client.rb +++ b/lib/zanzibar/client.rb @@ -6,9 +6,11 @@ require 'yaml' module Zanzibar ## - # Class for interacting with Secret Server + # Class for performing low-level WSDL actions against Secret Server class Client - ## Initializes the Savon client class variable with the wdsl document location and optional global variables + + ## + # Initializes the Savon client class variable with the wdsl document location and optional global variables # @param globals{}, optional def initialize(username, password, domain, wsdl, globals = {}) @username = username @@ -23,7 +25,8 @@ module Zanzibar end end - ## Get an authentication token for interacting with Secret Server. These are only good for about 10 minutes so just get a new one each time. + ## + # Get an authentication token for interacting with Secret Server. These are only good for about 10 minutes so just get a new one each time. # Will raise an error if there is an issue with the authentication. # @return the authentication token for the current user. def generate_token @@ -35,7 +38,8 @@ module Zanzibar raise "There was an error generating the authentiaton token for user #{@username}: #{err}" end - ## Get a secret returned as a hash + ## + # Get a secret returned as a hash # Will raise an error if there was an issue getting the secret # @param [Integer] the secret id # @return [Hash] the secret hash retrieved from the wsdl @@ -47,7 +51,8 @@ module Zanzibar raise "There was an error getting the secret with id #{scrt_id}: #{err}" end - ## Get the secret item id that relates to a key file or attachment. + ## + # Get the secret item id that relates to a key file or attachment. # Will raise on error # @param [Integer] the secret id # @param [String] the type of secret item to get, one of privatekey, publickey, attachment @@ -63,6 +68,12 @@ module Zanzibar end end + ## + # Get an "Attachment"-type file from a secret + # @param [Integer] the id of the secret + # @param [Integer] the id of the attachment on the secret + # @param [String] the type of the item being downloaded + # @return [Hash] contents and metadata of the downloaded file def download_file_attachment_by_item_id(scrt_id, secret_item_id, item_type, token = nil) token = generate_token unless token @client.call(:download_file_attachment_by_item_id, message: @@ -70,6 +81,8 @@ module Zanzibar .hash[:envelope][:body][:download_file_attachment_by_item_id_response][:download_file_attachment_by_item_id_result] end + ## + # Extract an item from a secret based on field name def get_secret_item_by_field_name(secret_items, field_name) secret_items.each do |item| return item if item[:field_name] == field_name diff --git a/lib/zanzibar/defaults.rb b/lib/zanzibar/defaults.rb index 20902c9..3a7e47f 100644 --- a/lib/zanzibar/defaults.rb +++ b/lib/zanzibar/defaults.rb @@ -2,15 +2,25 @@ require 'pathname' # Definitions for various strings used throughout the gem module Zanzibar + # The name of the binstub that invoked this code APPLICATION_NAME = Pathname.new($PROGRAM_NAME).basename + # The filename of the Zanzifile ZANZIFILE_NAME = 'Zanzifile'.freeze + # The filename of the resolved Zanzifile RESOLVED_NAME = 'Zanzifile.resolved'.freeze + # The template to use when writing the Zanzifile TEMPLATE_NAME = 'templates/Zanzifile.erb'.freeze + # The default value of the server when writing the Zanzifile DEFAULT_SERVER = 'secret.example.com'.freeze + # The default WSDL location for the Zanzifile template DEFAULT_WSDL = 'https://%s/webservices/sswebservice.asmx?wsdl'.freeze + # Error thrown when trying to overwrite an existing Zanzifile ALREADY_EXISTS_ERROR = "#{ZANZIFILE_NAME} already exists! Aborting...".freeze + # Error thrown when unable to construct the WSDL location NO_WSDL_ERROR = 'Could not construct WSDL URL. Please provide either --server or --wsdl'.freeze + # Error thrown when trying to download secrets from a Zanzifile that doesn't exist NO_ZANZIFILE_ERROR = "You don't have a #{ZANZIFILE_NAME}! Run `#{APPLICATION_NAME} init` first!".freeze + # Error thrown when a Zanzifile is missing necessary information INVALID_ZANZIFILE_ERROR = "Unable to load your #{ZANZIFILE_NAME}. Please ensure it is valid YAML.".freeze end diff --git a/lib/zanzibar/ui.rb b/lib/zanzibar/ui.rb index b8da719..29a3e73 100644 --- a/lib/zanzibar/ui.rb +++ b/lib/zanzibar/ui.rb @@ -1,40 +1,59 @@ require 'rubygems/user_interaction' module Zanzibar + ## # Prints messages out to stdout class Shell + ## + # The stream to write log messages (usually stdout) attr_writer :shell + ## + # Logging options and initializing stream def initialize(shell) @shell = shell @quiet = false @debug = ENV['DEBUG'] end + ## + # Write a debug message if debug is enabled def debug(message = nil) @shell.say(message || yield) if @debug && !@quiet end + ## + # Write an info message unless we have silenced output def info(message = nil) @shell.say(message || yield) unless @quiet end + ## + # Ask the user for confirmation unless we have silenced output def confirm(message = nil) @shell.say(message || yield, :green) unless @quiet end + ## + # Print a warning def warn(message = nil) @shell.say(message || yield, :yellow) end + ## + # Print an error def error(message = nil) @shell.say(message || yield, :red) end + ## + # Enable silent mode def be_quiet! @quiet = true end + ## + # Enable debug mode def debug! @debug = true end diff --git a/lib/zanzibar/version.rb b/lib/zanzibar/version.rb index 908af5a..06f0996 100644 --- a/lib/zanzibar/version.rb +++ b/lib/zanzibar/version.rb @@ -1,4 +1,5 @@ # The version of the gem module Zanzibar + # The Version of the application VERSION = '0.2.0'.freeze end