Class: Forward::CLI
- Inherits:
-
Object
- Object
- Forward::CLI
- Defined in:
- lib/forward/cli.rb
Constant Summary collapse
- BASIC_AUTH_REGEX =
/\A[^\s:]+:[^\s:]+\z/i- CNAME_REGEX =
/\A[a-z0-9]+(?:[\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}\z/i- SUBDOMAIN_PREFIX_REGEX =
/\A[a-z0-9]{1}[a-z0-9\-]+\z/i- USERNAME_REGEX =
PASSWORD_REGEX = /\A[^\s]+\z/i
- BANNER =
"Usage: forward <port> [options]\n forward <host> [options]\n forward <host:port> [options]\n\nDescription:\n\n Share a server running on localhost:port over the web by tunneling\n through Forward. A URL is created for each tunnel.\n\nSimple example:\n\n # You are developing a Rails site.\n\n > rails server &\n > forward 3000\n Forward created at https://mycompany.fwd.wf\n\nAssigning a static subdomain prefix:\n\n > rails server &\n > forward 3000 myapp\n Forward created at https://myapp-mycompany.fwd.wf\n\nVirtual Host example:\n\n # You are already running something on port 80 that uses\n # virtual host names.\n\n > forward mysite.dev\n Forward created at https://mycompany.fwd.wf\n\n"
Class Method Summary collapse
-
.authenticate ⇒ Object
Asks for the user’s email and password and puts them in a Hash.
-
.exit_with_error(message) ⇒ Object
Colors an error message red and displays it.
-
.forwardfile_path ⇒ Object
Returns a String file path for PWD/Forwardfile.
-
.logout ⇒ Object
Remove .forward file and SSH key (log a user out).
-
.parse_args_and_options(args) ⇒ Object
Parse arguments from CLI and options from Forwardfile.
-
.parse_cli_options(args) ⇒ Object
Parse non-published options and remove them from ARGV, then parse published options and update the options Hash with provided options and removes switches from ARGV.
-
.parse_forwarded(arg) ⇒ Object
Parses the arguments to determine if we’re forwarding a port or host and validates the port or host and updates @options if valid.
-
.parse_forwardfile ⇒ Object
Parse a local Forwardfile (in the PWD) and return it as a Hash.
-
.print_usage_and_exit ⇒ Object
Print the usage banner and Exit Code 0.
-
.run(args) ⇒ Object
Parses various options and arguments, validates everything to ensure we’re safe to proceed, and finally passes options to the Client.
-
.validate_cname(cname) ⇒ Object
Checks to make sure the cname is in the correct format and exits with an error message if it isn’t.
-
.validate_options(options) ⇒ Object
Validate all options in options Hash.
-
.validate_password(password) ⇒ Object
Checks to make sure the password is a valid format and exits with an error message if not.
-
.validate_port(port) ⇒ Object
Checks to make sure the port being set is a number between 1 and 65535 and exits with an error message if it’s not.
-
.validate_subdomain_prefix(prefix) ⇒ Object
Checks to make sure the subdomain prefix is in the correct format and exits with an error message if it isn’t.
-
.validate_username(username) ⇒ Object
Checks to make sure the username is a valid format and exits with an error message if not.
Class Method Details
.authenticate ⇒ Object
Asks for the user’s email and password and puts them in a Hash.
Returns a Hash with the email and password
225 226 227 228 229 230 231 232 |
# File 'lib/forward/cli.rb', line 225 def self.authenticate puts 'Enter your email and password' email = ask('email: ').chomp password = ask('password: ') { |q| q.echo = false }.chomp Forward.log.debug("Authenticating User: `#{email}:#{password.gsub(/./, 'x')}'") { :email => email, :password => password } end |
.exit_with_error(message) ⇒ Object
Colors an error message red and displays it.
message - error message String
268 269 270 271 272 |
# File 'lib/forward/cli.rb', line 268 def self.exit_with_error() Forward.log.fatal() puts HighLine.color(, :red) exit 1 end |
.forwardfile_path ⇒ Object
Returns a String file path for PWD/Forwardfile
91 92 93 |
# File 'lib/forward/cli.rb', line 91 def self.forwardfile_path File.join(Dir.pwd, 'Forwardfile') end |
.logout ⇒ Object
Remove .forward file and SSH key (log a user out)
235 236 237 238 239 240 241 |
# File 'lib/forward/cli.rb', line 235 def self.logout FileUtils.rm_f(Config.config_path) FileUtils.rm_f(Config.key_path) puts "You've been logged out. You'll be asked to log back in when you create a new tunnel." exit end |
.parse_args_and_options(args) ⇒ Object
Parse arguments from CLI and options from Forwardfile
args - An Array of command line arguments
Returns a Hash of options.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/forward/cli.rb', line 100 def self.(args) = { :host => '127.0.0.1', :port => 80 } Forward.log.debug("Default options: `#{options.inspect}'") if File.exist? forwardfile_path .merge!(parse_forwardfile) Forward.log.debug("Forwardfile options: `#{options.inspect}'") end .merge!((args)) forwarded, prefix = args[0..1] [:subdomain_prefix] = prefix unless prefix.nil? .merge!(parse_forwarded(forwarded)) Forward.log.debug("CLI options: `#{options.inspect}'") end |
.parse_cli_options(args) ⇒ Object
Parse non-published options and remove them from ARGV, then parse published options and update the options Hash with provided options and removes switches from ARGV.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/forward/cli.rb', line 45 def self.(args) Forward.log.debug("Parsing options") = {} @opts = OptionParser.new do |opts| opts. = BANNER.gsub(/^ {6}/, '') opts.separator '' opts.separator 'Options:' opts.on('-a', '--auth [USER:PASS]', 'Protect this tunnel with HTTP Basic Auth.') do |credentials| exit_with_error("Basic Auth: bad format, expecting USER:PASS") if credentials !~ BASIC_AUTH_REGEX username, password = credentials.split(':') [:username] = username [:password] = password end opts.on('-A', '--no-auth', 'Disable authentication on this tunnel (if a default is set in your preferences)') do |credentials| [:no_auth] = true end opts.on('-c', '--cname [CNAME]', 'Allow access to this tunnel as CNAME (you will need to setup a CNAME entry on your DNS server).') do |cname| [:cname] = cname.downcase end opts.on('--logout', 'Remove credentials to allow logging in as another user.' ) do logout end opts.on( '-h', '--help', 'Display this help.' ) do puts opts exit end opts.on('-v', '--version', 'Display version number.') do puts "forward #{VERSION}" exit end end @opts.parse!(args) end |
.parse_forwarded(arg) ⇒ Object
Parses the arguments to determine if we’re forwarding a port or host and validates the port or host and updates @options if valid.
arg - A String representing the port or host.
Returns a Hash containing the forwarded host or port
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/forward/cli.rb', line 142 def self.parse_forwarded(arg) Forward.log.debug("Forwarded: `#{arg}'") forwarded = {} if arg =~ /\A\d{1,5}\z/ port = arg.to_i forwarded[:port] = port elsif arg =~ /\A[-a-z0-9\.\-]+\z/i forwarded[:host] = arg elsif arg =~ /\A[-a-z0-9\.\-]+:\d{1,5}\z/i host, port = arg.split(':') port = port.to_i forwarded[:host] = host forwarded[:port] = port end forwarded end |
.parse_forwardfile ⇒ Object
Parse a local Forwardfile (in the PWD) and return it as a Hash. Raise an error and exit if unable to parse or result isn’t a Hash.
Returns a Hash of the options found in the Forwardfile
127 128 129 130 131 132 133 134 |
# File 'lib/forward/cli.rb', line 127 def self.parse_forwardfile = YAML.load_file(forwardfile_path) raise CLIError unless .kind_of?(Hash) .symbolize_keys rescue ArgumentError, SyntaxError, CLIError exit_with_error("Unable to parse #{forwardfile_path}") end |
.print_usage_and_exit ⇒ Object
Print the usage banner and Exit Code 0.
275 276 277 278 |
# File 'lib/forward/cli.rb', line 275 def self.print_usage_and_exit puts @opts exit end |
.run(args) ⇒ Object
Parses various options and arguments, validates everything to ensure we’re safe to proceed, and finally passes options to the Client.
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/forward/cli.rb', line 245 def self.run(args) ::HighLine.use_color = false if Forward.windows? if ARGV.include?('--debug') Forward.debug! ARGV.delete('--debug') elsif ARGV.include?('--rdebug') Forward.debug_remotely! ARGV.delete('--rdebug') end Forward.log.debug("Starting forward v#{Forward::VERSION}") = (args) () print_usage_and_exit if args.empty? && !File.exist?(forwardfile_path) Client.start() end |
.validate_cname(cname) ⇒ Object
Checks to make sure the cname is in the correct format and exits with an error message if it isn’t.
cname - cname String
196 197 198 199 |
# File 'lib/forward/cli.rb', line 196 def self.validate_cname(cname) Forward.log.debug("Validating CNAME: `#{cname}'") exit_with_error("`#{cname}' is an invalid domain format") unless cname =~ CNAME_REGEX end |
.validate_options(options) ⇒ Object
Validate all options in options Hash.
options - the options Hash
213 214 215 216 217 218 219 220 |
# File 'lib/forward/cli.rb', line 213 def self.() Forward.log.debug("Validating options: `#{options.inspect}'") .each do |key, value| next if value.nil? validate_method = :"validate_#{key}" send(validate_method, value) if respond_to?(validate_method) end end |
.validate_password(password) ⇒ Object
Checks to make sure the password is a valid format and exits with an error message if not.
password - password String
187 188 189 190 |
# File 'lib/forward/cli.rb', line 187 def self.validate_password(password) Forward.log.debug("Validating Password: `#{password}'") exit_with_error("`#{password}' is an invalid password format") unless password =~ PASSWORD_REGEX end |
.validate_port(port) ⇒ Object
Checks to make sure the port being set is a number between 1 and 65535 and exits with an error message if it’s not.
port - port number Integer
167 168 169 170 171 172 |
# File 'lib/forward/cli.rb', line 167 def self.validate_port(port) Forward.log.debug("Validating Port: `#{port}'") unless port.between?(1, 65535) exit_with_error "Invalid Port: #{port} is an invalid port number" end end |
.validate_subdomain_prefix(prefix) ⇒ Object
Checks to make sure the subdomain prefix is in the correct format and exits with an error message if it isn’t.
prefix - subdomain prefix String
205 206 207 208 |
# File 'lib/forward/cli.rb', line 205 def self.validate_subdomain_prefix(prefix) Forward.log.debug("Validating Subdomain Prefix: `#{prefix}'") exit_with_error("`#{prefix}' is an invalid subdomain prefix format") unless prefix =~ SUBDOMAIN_PREFIX_REGEX end |
.validate_username(username) ⇒ Object
Checks to make sure the username is a valid format and exits with an error message if not.
username - username String
178 179 180 181 |
# File 'lib/forward/cli.rb', line 178 def self.validate_username(username) Forward.log.debug("Validating Username: `#{username}'") exit_with_error("`#{username}' is an invalid username format") unless username =~ USERNAME_REGEX end |