vps_cli 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/Rakefile +20 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/vps-cli +6 -0
- data/example_credentials.yaml +39 -0
- data/exe/vps-cli +6 -0
- data/lib/vps_cli/access.rb +176 -0
- data/lib/vps_cli/cli.rb +99 -0
- data/lib/vps_cli/configuration.rb +78 -0
- data/lib/vps_cli/configurations/default_configuration.rb +44 -0
- data/lib/vps_cli/configurations/testing_configuration.rb +25 -0
- data/lib/vps_cli/copy.rb +146 -0
- data/lib/vps_cli/helpers/access_helper.rb +132 -0
- data/lib/vps_cli/helpers/file_helper.rb +146 -0
- data/lib/vps_cli/helpers/github_http.rb +107 -0
- data/lib/vps_cli/install.rb +137 -0
- data/lib/vps_cli/packages.rb +22 -0
- data/lib/vps_cli/pull.rb +110 -0
- data/lib/vps_cli/setup.rb +105 -0
- data/lib/vps_cli/version.rb +3 -0
- data/lib/vps_cli.rb +90 -0
- data/sops_testing_key.asc +125 -0
- data/unencrypted_example_credentials.yaml +19 -0
- data/vps_cli.gemspec +46 -0
- metadata +176 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'vps_cli'
|
4
|
+
|
5
|
+
VpsCli.configure do |config|
|
6
|
+
# Where items will be copied to
|
7
|
+
# For example, the local dir is where you would your dotfiles
|
8
|
+
# saved to
|
9
|
+
config.local_dir = Dir.home
|
10
|
+
config.backup_dir = File.join(Dir.home, 'backup_files')
|
11
|
+
config.local_sshd_config = File.join('/etc', 'ssh', 'sshd_config')
|
12
|
+
|
13
|
+
# You must set these values yourself
|
14
|
+
|
15
|
+
# Location of your config files
|
16
|
+
# config.config_files = File.join(Dir.home, 'config_files')
|
17
|
+
# This is just used for easier git pulling and git pushing
|
18
|
+
|
19
|
+
config.config_files = File.join(Dir.home, 'vps_setup')
|
20
|
+
|
21
|
+
# Location of your dotfiles
|
22
|
+
# config.dotfiles = File.join(Dir.home, 'vps_setup', 'dotfiles')
|
23
|
+
config.dotfiles = File.join(config.config_files, 'dotfiles')
|
24
|
+
|
25
|
+
# Location of your dotfiles
|
26
|
+
# config.dotfiles = File.join(Dir.home, 'config_files', 'dotfiles')
|
27
|
+
config.misc_files = File.join(config.config_files, 'misc_files')
|
28
|
+
|
29
|
+
# credentials.yaml file, wherever its located, for me I have it in the home dir
|
30
|
+
config.credentials = File.join(Dir.home, '.credentials.yaml')
|
31
|
+
|
32
|
+
# location of your .netrc file, usually ~/.netrc
|
33
|
+
config.netrc = File.join(Dir.home, '.netrc')
|
34
|
+
|
35
|
+
config.verbose = false
|
36
|
+
|
37
|
+
# Change to false if you dont want to be prompted
|
38
|
+
# about file creations / overwrites
|
39
|
+
config.interactive = true
|
40
|
+
|
41
|
+
# this is merely for testing purposes, dont worry about this
|
42
|
+
config.testing = false
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'vps_cli'
|
4
|
+
|
5
|
+
test_dir = File.expand_path('../../../test', __dir__)
|
6
|
+
|
7
|
+
VpsCli.configure do |config|
|
8
|
+
config.local_dir = File.join(test_dir, 'local_dir')
|
9
|
+
config.backup_dir = File.join(test_dir, 'backup_dir')
|
10
|
+
config.local_sshd_config = File.join(config.local_dir, 'sshd_config')
|
11
|
+
config.sshd_backup = File.join(config.backup_dir, 'sshd_config.orig')
|
12
|
+
|
13
|
+
config.config_files = File.join(test_dir, 'config_files')
|
14
|
+
config.misc_files = File.join(config.config_files, 'miscfiles')
|
15
|
+
config.dotfiles = File.join(config.config_files, 'dotfiles')
|
16
|
+
config.credentials = File.join(File.expand_path('../../../', __dir__), 'example_credentials.yaml')
|
17
|
+
config.netrc = File.join(test_dir, 'access_dir', 'netrc')
|
18
|
+
|
19
|
+
|
20
|
+
config.verbose = true
|
21
|
+
config.interactive = false
|
22
|
+
config.testing = true
|
23
|
+
end
|
24
|
+
|
25
|
+
# puts VpsCli.configuration.local_dir
|
data/lib/vps_cli/copy.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
require 'vps_cli/helpers/file_helper'
|
6
|
+
|
7
|
+
module VpsCli
|
8
|
+
# Copies config from /vps_cli/config_files/dotfiles
|
9
|
+
# & vps_cli/config_files/miscfiles to your home dir
|
10
|
+
class Copy
|
11
|
+
extend FileHelper
|
12
|
+
|
13
|
+
# Top level method for copying all files
|
14
|
+
# Will use the configurations set by VpsCli.configuration
|
15
|
+
# unless passed a different config
|
16
|
+
# @raise [RuntimeError]
|
17
|
+
# Will raise this error if you run this method as root or sudo
|
18
|
+
def self.all(config = VpsCli.configuration)
|
19
|
+
# raises an error if the script is run as root
|
20
|
+
return unless root? == false
|
21
|
+
|
22
|
+
# fills in options that are not explicitly filled in
|
23
|
+
FileHelper.mkdirs(config.local_dir, config.backup_dir)
|
24
|
+
|
25
|
+
# copies dotfiles
|
26
|
+
dotfiles(config)
|
27
|
+
|
28
|
+
# copies gnome_settings
|
29
|
+
gnome_settings(config)
|
30
|
+
|
31
|
+
# copies sshd_config
|
32
|
+
sshd_config(config)
|
33
|
+
|
34
|
+
puts "dotfiles copied to #{config.local_dir}"
|
35
|
+
puts "backups created @ #{config.backup_dir}"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Copy files from 'config_files/dotfiles' directory via the copy_all method
|
39
|
+
# Defaults are provided in the VpsCli.create_options method
|
40
|
+
# @see VpsCli::Configuration
|
41
|
+
def self.dotfiles(config = VpsCli.configuration)
|
42
|
+
Dir.each_child(config.dotfiles) do |file|
|
43
|
+
config_file = File.join(config.dotfiles, file)
|
44
|
+
local = File.join(config.local_dir, ".#{file}")
|
45
|
+
backup = File.join(config.backup_dir, "#{file}.orig")
|
46
|
+
|
47
|
+
files_and_dirs(config_file: config_file,
|
48
|
+
local_file: local,
|
49
|
+
backup_file: backup,
|
50
|
+
verbose: config.verbose,
|
51
|
+
interactive: config.interactive)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Checks that sshd_config is able to be copied
|
56
|
+
# @param sshd_config [File] File containing your original sshd_config
|
57
|
+
# Defaults to /etc/ssh/sshd_config
|
58
|
+
# @return [Boolean] Returns true if the sshd_config exists
|
59
|
+
def self.sshd_copyable?(sshd_config = nil)
|
60
|
+
sshd_config ||= '/etc/ssh/sshd_config'
|
61
|
+
|
62
|
+
no_sshd_config = 'No sshd_config found. sshd_config not copied'
|
63
|
+
|
64
|
+
return true if File.exist?(sshd_config)
|
65
|
+
|
66
|
+
VpsCli.errors << Exception.new(no_sshd_config)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Copies sshd_config to the VpsCli.configuration.local_sshd_config
|
70
|
+
# location
|
71
|
+
# Defaults to [/etc/ssh/sshd_config] if not set
|
72
|
+
# This is slightly different from other copy methods in this file
|
73
|
+
# It uses Rake.sh("sudo cp")
|
74
|
+
# Due to copying to /etc/ssh/sshd_config requiring root permissions
|
75
|
+
def self.sshd_config(config = VpsCli.configuration)
|
76
|
+
|
77
|
+
config.local_sshd_config ||= File.join('/etc', 'ssh', 'sshd_config')
|
78
|
+
return unless sshd_copyable?(config.local_sshd_config)
|
79
|
+
|
80
|
+
config.sshd_backup ||= File.join(config.backup_dir, 'sshd_config.orig')
|
81
|
+
|
82
|
+
misc_sshd_path = File.join(config.misc_files, 'sshd_config')
|
83
|
+
|
84
|
+
if File.exist?(config.local_sshd_config) && !File.exist?(config.sshd_backup)
|
85
|
+
Rake.cp(config.local_sshd_config, config.sshd_backup)
|
86
|
+
else
|
87
|
+
puts "#{config.sshd_backup} already exists. no backup created"
|
88
|
+
end
|
89
|
+
|
90
|
+
return Rake.cp(misc_sshd_path, config.local_sshd_config) if config.testing
|
91
|
+
|
92
|
+
# This method must be run this way due to it requiring root privileges
|
93
|
+
unless FileHelper.overwrite?(config.local_sshd_config, config.interactive)
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
Rake.sh("sudo cp #{misc_sshd_path} #{config.local_sshd_config}")
|
98
|
+
end
|
99
|
+
|
100
|
+
# Deciphers between files & directories
|
101
|
+
# Also utilizes the settings from your configuration to properly
|
102
|
+
# copy things
|
103
|
+
# @see VpsCli::FileHelper#copy_dirs
|
104
|
+
# @see VpsCli::FileHelper#copy_files
|
105
|
+
def self.files_and_dirs(opts = {})
|
106
|
+
if File.directory?(opts[:config_file])
|
107
|
+
FileHelper.copy_dirs(opts)
|
108
|
+
else
|
109
|
+
FileHelper.copy_files(opts)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Copies gnome terminal via dconf
|
114
|
+
# @see https://wiki.gnome.org/Projects/dconf dconf wiki
|
115
|
+
# @param config [VpsCli::Configuration] Where to save the current gnome terminal settings
|
116
|
+
# @note This method will raise an error if dconf errors out
|
117
|
+
# The error will be saved to VpsCli.errors
|
118
|
+
def self.gnome_settings(config = VpsCli.configuration)
|
119
|
+
backup = "#{config.backup_dir}/gnome_terminal_settings.orig"
|
120
|
+
|
121
|
+
# This is the ONLY spot for gnome terminal
|
122
|
+
gnome_path = '/org/gnome/terminal/'
|
123
|
+
gnome_file = File.join(config.misc_files, 'gnome_terminal_settings')
|
124
|
+
|
125
|
+
raise RuntimeError if config.testing
|
126
|
+
raise RuntimeError unless File.exists?(gnome_file)
|
127
|
+
|
128
|
+
overwrite = proc { |file| FileHelper.overwrite?(file, config.interactive) }
|
129
|
+
Rake.sh("dconf dump #{gnome_path} > #{backup}") if overwrite.call(backup)
|
130
|
+
|
131
|
+
dconf_load = "dconf load #{gnome_path} < #{config.misc_files}/gnome_terminal_settings"
|
132
|
+
Rake.sh(dconf_load) if overwrite.call(gnome_path)
|
133
|
+
rescue RuntimeError => error
|
134
|
+
puts 'something went wrong with gnome, continuing on' if config.verbose
|
135
|
+
VpsCli.errors << error
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.root?
|
139
|
+
root = (Process.uid.zero? || Dir.home == '/root')
|
140
|
+
root_msg = 'Do not run this as root or sudo. Run as a normal user'
|
141
|
+
raise root_msg if root == true
|
142
|
+
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @see https://ruby-doc.org/stdlib-2.6.0.preview2/libdoc/open3/rdoc/Open3.html
|
4
|
+
require 'open3'
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
# Helper methods to be used within Access to help reduce the file size
|
9
|
+
module AccessHelper
|
10
|
+
# retrieves the values of .netrc for heroku and creates a writable string
|
11
|
+
# @return [String] Returns the string to be written to netrc
|
12
|
+
def heroku_api_string(yaml_file:)
|
13
|
+
# initial tree traversal in the .yaml file
|
14
|
+
heroku_api = %i[heroku api]
|
15
|
+
heroku_api_keys = %i[machine login password]
|
16
|
+
|
17
|
+
make_string(base: heroku_api, keys: heroku_api_keys) do |path|
|
18
|
+
decrypt(yaml_file: yaml_file, path: path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# retries the git values for heroku in your .yaml file
|
23
|
+
# @return [String] Returns the string to be written to your netrc file
|
24
|
+
def heroku_git_string(yaml_file:)
|
25
|
+
heroku_git = %i[heroku git]
|
26
|
+
heroku_git_keys = %i[machine login password]
|
27
|
+
|
28
|
+
make_string(base: heroku_git, keys: heroku_git_keys) do |path|
|
29
|
+
decrypt(yaml_file: yaml_file, path: path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# my version of Enumerable#inject intended to return a string
|
34
|
+
# provides a count to know what # object youre on
|
35
|
+
# @param array [Array<#to_s>]
|
36
|
+
# For each element in the array, yield to the block given.
|
37
|
+
# @yieldparam accum [String]
|
38
|
+
# The value that will persist throughout the block
|
39
|
+
# @yieldparam element [String] The current element in the array
|
40
|
+
# @yield param count [Integer]
|
41
|
+
# @return [String] Returns the string returned by the block passed to it
|
42
|
+
def my_inject_with_count(array)
|
43
|
+
value = nil
|
44
|
+
count = 0
|
45
|
+
array.inject('') do |accum, element|
|
46
|
+
value = yield(accum, element, count)
|
47
|
+
count += 1
|
48
|
+
value # if not here, returns the value of count
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates a string to be used to write to .netrc
|
53
|
+
# @param base [String] Provides the base string from which to add to
|
54
|
+
# @param keys [Array<String>] An array of strings to append to base
|
55
|
+
# @return [String] Returns the string after concatenating them
|
56
|
+
def make_string(base:, keys:)
|
57
|
+
# iterates through the keys to provide a path to each array
|
58
|
+
# essentialy is the equivalent of Hash.dig(:heroku, :api, :key)
|
59
|
+
my_inject_with_count(keys) do |string, key, count|
|
60
|
+
path = dig_for_path(base, key)
|
61
|
+
|
62
|
+
value = yield(path)
|
63
|
+
value << "\n " if count < keys.length - 1
|
64
|
+
string + value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Writes the value of string to netrc
|
69
|
+
# @param netrc_file [File] ($HOME/.netrc)
|
70
|
+
# The location of your .netrc file to be read by heroku
|
71
|
+
# @param string [String] The String to write to the netrc file
|
72
|
+
# @return void
|
73
|
+
def write_to_netrc(netrc_file: nil, string:)
|
74
|
+
netrc_file ||= File.join(Dir.home, '.netrc')
|
75
|
+
Rake.mkdir_p(File.dirname(netrc_file))
|
76
|
+
Rake.touch(netrc_file) unless File.exist?(netrc_file)
|
77
|
+
|
78
|
+
begin
|
79
|
+
File.write(netrc_file, string)
|
80
|
+
rescue Errno::EACCES => e
|
81
|
+
netrc_error(netrc_file: netrc_file, error: e)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Adds the error to VpsCli#errors array
|
86
|
+
# @param [File] Location of netrc_file
|
87
|
+
# @param [Exception] The error to write to the array
|
88
|
+
# @return void
|
89
|
+
def netrc_error(netrc_file:, error:)
|
90
|
+
error_msg = "Unable to write to your #{netrc_file}."
|
91
|
+
VpsCli.errors << error.exception(error_msg)
|
92
|
+
end
|
93
|
+
|
94
|
+
# uses an access file via SOPS
|
95
|
+
# SOPS is an encryption tool
|
96
|
+
# @see https://github.com/mozilla/sops
|
97
|
+
# It will decrypt the file, please use a .yaml file
|
98
|
+
# @param file [File]
|
99
|
+
# The .yaml file encrypted with sops used to login to various accounts
|
100
|
+
# @path [String] JSON formatted string to traverse
|
101
|
+
# a yaml file tree
|
102
|
+
# Example: "[\"github\"][\"username\"]"
|
103
|
+
# @return [String] The value of key given in the .yaml file
|
104
|
+
def decrypt(yaml_file:, path:)
|
105
|
+
# puts all keys into a ["key"] within the array
|
106
|
+
sops_cmd = "sops -d --extract '#{path}' #{yaml_file}"
|
107
|
+
|
108
|
+
# this allows you to enter your passphrase
|
109
|
+
export_tty
|
110
|
+
# this will return in the string form the value you were looking for
|
111
|
+
stdout, _stderr, _status = Open3.capture3(sops_cmd)
|
112
|
+
|
113
|
+
stdout
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param [#to_s, Array<#to_s>] The ordered path to traverse
|
117
|
+
# @return [String] Returns a path string to be able to traverse a yaml file
|
118
|
+
# @see VpsCli::Access#decrypt
|
119
|
+
def dig_for_path(*path)
|
120
|
+
path.flatten.inject('') do |final_path, node|
|
121
|
+
final_path + "[#{node.to_s.to_json}]"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# I noticed needing to export $(tty) while troubleshooting
|
126
|
+
# issues with gpg keys. It is here just in case its not in
|
127
|
+
# your zshrc / bashrc file
|
128
|
+
# @return void
|
129
|
+
def export_tty
|
130
|
+
Rake.sh('GPG_TTY=$(tty) && export GPG_TTY')
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
# Used for copying files, making directories, copying directories etc
|
6
|
+
module FileHelper
|
7
|
+
# Helper method for making multiple directories
|
8
|
+
# @param [Dir, Array<Dir>] Creates either one, or multiple directories
|
9
|
+
def self.mkdirs(*dirs)
|
10
|
+
dirs.flatten.each { |dir| Rake.mkdir_p(dir) unless Dir.exist?(dir) }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Copies files, called by copy_all
|
14
|
+
# @see VpsCli::Copy#all
|
15
|
+
# @param [Hash] opts The options to copy with
|
16
|
+
# @option opts [File] :config_file The file from the repo to be copied locally
|
17
|
+
# @option opts [File] :local_file The file that is currently present locally
|
18
|
+
# @option opts [File] :backup_file
|
19
|
+
# The file to which to save the currently present local file
|
20
|
+
# @option opts [Boolean] :interactive
|
21
|
+
# Will prompt yes or no for each file it creates
|
22
|
+
# @option opts [Boolean] :verbose Will print more info to terminal if true
|
23
|
+
def self.copy_files(opts = {})
|
24
|
+
# if there is an original dot file & no backup file in the backupdir
|
25
|
+
# Copy the dot file to the backup dir
|
26
|
+
if create_backup?(opts)
|
27
|
+
copy_file(opts[:local_file], opts[:backup_file], opts[:interactive])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Copies from vps_cli/dotfiles to the location of the dot_file
|
31
|
+
copy_file(opts[:config_file], opts[:local_file], opts[:interactive])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Copies directories instead of files, called by copy_all
|
35
|
+
# @see VpsCli::Copy#all
|
36
|
+
# @param [Hash] opts The options to copy with
|
37
|
+
# @option opts [File] :config_file The file from the repo to be copied locally
|
38
|
+
# @option opts [File] :dot_file The file that is currently present locally
|
39
|
+
# @option opts [File] :backup_file
|
40
|
+
# The file to which to save the currently present local file
|
41
|
+
# @option opts [Boolean] :interactive
|
42
|
+
# Will prompt yes or no for each file it creates
|
43
|
+
# @option opts [Boolean] :verbose Will print more info to terminal if true
|
44
|
+
def self.copy_dirs(opts = {})
|
45
|
+
mkdirs(opts[:local_file])
|
46
|
+
|
47
|
+
if create_backup?(opts)
|
48
|
+
copy_dir(opts[:local_file], opts[:backup_file], opts[:interactive])
|
49
|
+
end
|
50
|
+
|
51
|
+
Dir.each_child(opts[:config_file]) do |dir|
|
52
|
+
dir = File.join(opts[:config_file], dir)
|
53
|
+
|
54
|
+
# copies to local dir
|
55
|
+
copy_dir(dir, opts[:local_file], opts[:interactive])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Checks that a backup file does not exist
|
60
|
+
# @param file [File] File to be searched for
|
61
|
+
# @param verbose [Boolean] Will print to console if verbose == true
|
62
|
+
# @return [Boolean] Returns true if the file is not found
|
63
|
+
def self.backup_file_not_found?(file, verbose = false)
|
64
|
+
return true unless File.exist?(file)
|
65
|
+
|
66
|
+
puts "#{file} exists already. No backup created." if verbose
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# Helper method for determining whether or not to create a backup file
|
71
|
+
# @param opts [Hash] options hash
|
72
|
+
# @option [File] :local_file current dot file
|
73
|
+
# @option [File] :backup_file Where to back the dot file up to
|
74
|
+
# @option [Boolean] :verbose Will print to terminal if verbose == true
|
75
|
+
# @return [Boolean] Returns true if there is a dotfile that exists
|
76
|
+
# And there is no current backup_file found
|
77
|
+
def self.create_backup?(opts = {})
|
78
|
+
return false unless file_found?(opts[:local_file], opts[:verbose])
|
79
|
+
unless backup_file_not_found?(opts[:backup_file], opts[:verbose])
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Default way of checking if the dotfile already exists
|
87
|
+
# @param file [File] File to be searched for
|
88
|
+
# @param verbose [Boolean] Will print to console if verbose == true
|
89
|
+
# @return [Boolean] Returns true if the file exists
|
90
|
+
def self.file_found?(file, verbose = false)
|
91
|
+
return true if File.exist?(file)
|
92
|
+
|
93
|
+
puts "#{file} does not exist. No backup created." if verbose
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.retrieve_file(directory, name)
|
98
|
+
Dir.children(directory).select { |file| name == file }
|
99
|
+
end
|
100
|
+
|
101
|
+
# base method to copy a file and ask for permission prior to copying
|
102
|
+
# @see copy_files
|
103
|
+
# @see ask_permission
|
104
|
+
# @param from [File] File to copy from
|
105
|
+
# @param to [File] File to copy to
|
106
|
+
# @param config [VpsCli::Configuration] (VpsCli#configuration)
|
107
|
+
# uses the default config provided by the VpsCli module
|
108
|
+
def self.copy_file(from, to, interactive = false)
|
109
|
+
Rake.cp(from, to) if overwrite?(to, interactive)
|
110
|
+
end
|
111
|
+
|
112
|
+
# base method to copy a dir and ask for permission prior to copying
|
113
|
+
# @see copy_dirs
|
114
|
+
# @see ask_permission
|
115
|
+
# @param from [Dir] Directory to copy from
|
116
|
+
# @param to [Dir] Directory to copy to
|
117
|
+
# @param interactive [Boolean] (false) asks whether or not to create the file
|
118
|
+
def self.copy_dir(from, to, interactive = false)
|
119
|
+
mkdirs(to)
|
120
|
+
to_path = File.join(to, File.basename(from))
|
121
|
+
Rake.cp_r(from, to) if overwrite?(to_path, interactive)
|
122
|
+
end
|
123
|
+
|
124
|
+
# asks permission to copy a file
|
125
|
+
# @param file [File] The file to copy to
|
126
|
+
# @param interactive [Boolean] (false) If interactive equals false
|
127
|
+
# then automatically overwrite
|
128
|
+
# @return [Boolean]
|
129
|
+
# Decides whether or not the file will be created / overwritted
|
130
|
+
def self.overwrite?(file, interactive = false)
|
131
|
+
return true if interactive == false
|
132
|
+
|
133
|
+
string = "Attempting to overwrite file #{file}" if File.exist?(file)
|
134
|
+
string ||= "Attempting to create file #{file}"
|
135
|
+
|
136
|
+
# +string is equivalent to string.dup
|
137
|
+
string = +string + ' Is this okay? (Y/N)'
|
138
|
+
|
139
|
+
loop do
|
140
|
+
puts string
|
141
|
+
input = $stdin.gets.chomp.downcase.to_sym
|
142
|
+
return true if input == :y
|
143
|
+
return false if input == :n
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module VpsCli
|
7
|
+
# An http wrapper for github api request
|
8
|
+
class GithubHTTP
|
9
|
+
attr_accessor :uri, :title
|
10
|
+
attr_writer :token, :ssh_file
|
11
|
+
|
12
|
+
# @param uri [URI] the url to hit
|
13
|
+
# @param token [String] Github API token to use
|
14
|
+
# @param ssh_key [String] Your ssh file IE: ~/.ssh/id_rsa.pub
|
15
|
+
# @param title [String] The title of your ssh key
|
16
|
+
# Ensure it is in the format: "token 14942842859"
|
17
|
+
def initialize(uri:, token:, ssh_file:, title:)
|
18
|
+
@uri = uri
|
19
|
+
@token = token
|
20
|
+
@ssh_file = ssh_file
|
21
|
+
@ssh_key = File.read(ssh_file)
|
22
|
+
@headers = headers(token: token)
|
23
|
+
@title = title
|
24
|
+
end
|
25
|
+
|
26
|
+
# The headers need for authorization of a request
|
27
|
+
# @param token [String] (nil) Your github API token
|
28
|
+
# @see https://github.com/settings/keys
|
29
|
+
# make sure your token has write:public_key and read:public_key access
|
30
|
+
# @return [Hash] Returns a hash of headers
|
31
|
+
def headers(token:)
|
32
|
+
json = 'application/json'
|
33
|
+
|
34
|
+
{ 'Content-Type' => json,
|
35
|
+
'Accepts' => json,
|
36
|
+
'Authorization' => token }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the appropriate json string to write an ssh key
|
40
|
+
# @return [String] Returns a json formatted string to write an ssh key
|
41
|
+
def ssh_json_string
|
42
|
+
{ 'title' => @title,
|
43
|
+
'key' => @ssh_key }.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
# base method for an http connection
|
47
|
+
# @yieldparam http [Net::HTTP] yields the http class
|
48
|
+
# @return Whatever the value of yield is
|
49
|
+
def start_connection
|
50
|
+
Net::HTTP.start(@uri.host, @uri.port, use_ssl: true) do |http|
|
51
|
+
yield(http)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Pushes your public key to github
|
56
|
+
# to push your ssh key to the github
|
57
|
+
# @return Net::HTTPResponse
|
58
|
+
def push_ssh_key
|
59
|
+
get = get_request
|
60
|
+
|
61
|
+
post = post_request(data: ssh_json_string)
|
62
|
+
|
63
|
+
response = start_connection do |http|
|
64
|
+
get_response = http.request(get)
|
65
|
+
|
66
|
+
ssh_keys_json = get_response.body
|
67
|
+
return ssh_key_found_msg if ssh_key_exist?(json_string: ssh_keys_json)
|
68
|
+
|
69
|
+
http.request(post)
|
70
|
+
end
|
71
|
+
|
72
|
+
VpsCli.errors << response if response != Net::HTTPCreated
|
73
|
+
|
74
|
+
puts 'ssh key pushed to github' if response.class == Net::HTTPCreated
|
75
|
+
response
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param token [String] Your github api token
|
79
|
+
# @return [Net::HTTP::Get] Returns a new get request class
|
80
|
+
def get_request
|
81
|
+
Net::HTTP::Get.new(@uri, @headers)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param data [String] The data to send in the post request, must be json
|
85
|
+
# @return [Net::HTTP::Post] Returns a new post request class
|
86
|
+
def post_request(data:)
|
87
|
+
post = Net::HTTP::Post.new(@uri, @headers)
|
88
|
+
post.body = data
|
89
|
+
post
|
90
|
+
end
|
91
|
+
|
92
|
+
# Checks if the ssh key is already found
|
93
|
+
def ssh_key_exist?(json_string:)
|
94
|
+
# just in case your ssh key has a comment in it
|
95
|
+
# keys pulled from github will not have comments
|
96
|
+
ssh_key = @ssh_key.split('==')[0].concat('==')
|
97
|
+
|
98
|
+
JSON.parse(json_string).any? do |data|
|
99
|
+
data['key'] == ssh_key
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def ssh_key_found_msg
|
104
|
+
puts 'The ssh key provided is already on github, no post request made.'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|