Skip to content
This repository was archived by the owner on Oct 22, 2020. It is now read-only.

Commit 8f22ca9

Browse files
committed
Add --version and --update switches
1 parent 4ead98d commit 8f22ca9

File tree

5 files changed

+213
-1
lines changed

5 files changed

+213
-1
lines changed

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.1.0

env.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
require 'wpxf/utility/text'
2121
require 'wpxf/utility/reference_inflater'
2222

23+
require 'github_updater'
24+
2325
module Wpxf
2426
def self.data_directory=(val)
2527
@@data_directory = val
@@ -29,6 +31,14 @@ def self.data_directory
2931
@@data_directory
3032
end
3133

34+
def self.app_path=(val)
35+
@@app_path = val
36+
end
37+
38+
def self.app_path
39+
@@app_path
40+
end
41+
3242
def self.change_stdout_sync(enabled)
3343
original_setting = STDOUT.sync
3444
STDOUT.sync = true
@@ -37,4 +47,5 @@ def self.change_stdout_sync(enabled)
3747
end
3848
end
3949

50+
Wpxf.app_path = app_path
4051
Wpxf.data_directory = File.join(app_path, 'data/')

github_updater.rb

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
require 'json'
2+
require 'typhoeus'
3+
require 'fileutils'
4+
5+
module Wpxf
6+
# A self updater that uses the latest release from GitHub as the target.
7+
class GitHubUpdater
8+
def latest_release_url
9+
'https://api.github.com/repos/rastating/wordpress-exploit-framework/releases/latest'
10+
end
11+
12+
# Get information about the latest update available on GitHub.
13+
# @param current_version [String] the current version number in use.
14+
# @return [Hash, nil] a hash containing the :release_notes, :zip_url and :release_name, or nil if there is no update.
15+
def get_update(current_version)
16+
res = Typhoeus.get(latest_release_url)
17+
return nil unless res && res.code == 200
18+
19+
begin
20+
update = JSON.parse(res.body)
21+
rescue JSON::ParserError
22+
return nil
23+
end
24+
25+
begin
26+
return nil if Gem::Version.new(current_version) >= Gem::Version.new(update['tag_name'].sub(/^v/, ''))
27+
rescue
28+
return nil
29+
end
30+
31+
{ release_notes: update['body'], zip_url: update['zipball_url'], release_name: update['name'] }
32+
end
33+
34+
# Download and apply an update from the specified URL.
35+
# @param zip_url [String] the URL to fetch the update from.
36+
def download_and_apply_update(zip_url)
37+
tmp = create_tmp_directory
38+
zip_filename = File.join(tmp, 'update.zip')
39+
40+
download_update_zip(zip_url, zip_filename)
41+
42+
Zip::File.open(zip_filename) do |zip_file|
43+
zip_file.each do |entry|
44+
entry.extract File.join(tmp, entry.name)
45+
end
46+
end
47+
48+
Dir.glob(File.join(tmp, 'rastating-wordpress-exploit-framework*/*')) do |f|
49+
FileUtils.cp_r(f, Wpxf.app_path)
50+
end
51+
52+
FileUtils.rm_rf(tmp)
53+
end
54+
55+
private
56+
57+
def create_tmp_directory
58+
tmp = File.join(Dir.tmpdir, "wpxf_update_#{object_id}")
59+
FileUtils.mkdir_p(tmp)
60+
tmp
61+
end
62+
63+
def download_update_zip(zip_url, local_filename)
64+
zip = File.open(local_filename, 'wb')
65+
request = Typhoeus::Request.new(zip_url, followlocation: true)
66+
request.on_headers do |response|
67+
raise 'Request failed' if response.code != 200
68+
end
69+
70+
request.on_body do |chunk|
71+
zip.write(chunk)
72+
end
73+
74+
request.on_complete do
75+
zip.close
76+
end
77+
78+
request.run
79+
end
80+
end
81+
end

spec/github_updater_spec.rb

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
require_relative 'spec_helper'
2+
3+
describe Wpxf::GitHubUpdater do
4+
let(:typhoeus_return_code) { :ok }
5+
let(:typhoeus_code) { 200 }
6+
let(:typhoeus_body) { '' }
7+
let(:typhoeus_headers) { { 'Content-Type' => 'text/html; charset=utf-8' } }
8+
let(:subject) { Wpxf::GitHubUpdater.new }
9+
10+
before :each do
11+
Typhoeus.stub(/.*/) do
12+
Typhoeus::Response.new(
13+
code: typhoeus_code,
14+
body: typhoeus_body,
15+
headers: typhoeus_headers,
16+
return_code: typhoeus_return_code
17+
)
18+
end
19+
end
20+
21+
describe '#get_update' do
22+
context 'when the API returns a status other than 200' do
23+
let(:typhoeus_code) { 404 }
24+
25+
it 'returns nil' do
26+
expect(subject.get_update('')).to be_nil
27+
end
28+
end
29+
30+
context 'when invalid JSON is returned from the API' do
31+
let(:typhoeus_body) { 'invalid body' }
32+
33+
it 'returns nil' do
34+
expect(subject.get_update('')).to be_nil
35+
end
36+
end
37+
38+
context 'when the version number from GitHub is invalid' do
39+
let(:typhoeus_body) do
40+
{ tag_name: 'invalid version' }.to_json
41+
end
42+
43+
it 'returns nil' do
44+
expect(subject.get_update('1.0')).to be_nil
45+
end
46+
end
47+
48+
context 'when the current version number is invalid' do
49+
let(:typhoeus_body) do
50+
{ tag_name: '1.1' }.to_json
51+
end
52+
53+
it 'returns nil' do
54+
expect(subject.get_update('invalid')).to be_nil
55+
end
56+
end
57+
58+
context 'when the current version is the same as the latest GitHub release' do
59+
let(:typhoeus_body) do
60+
{ tag_name: '1.1' }.to_json
61+
end
62+
63+
it 'returns nil' do
64+
expect(subject.get_update('1.1')).to be_nil
65+
end
66+
end
67+
68+
context 'when the current version is older than the latest GitHub release' do
69+
let(:typhoeus_body) do
70+
{
71+
tag_name: 'v1.1',
72+
body: 'notes',
73+
zipball_url: 'url',
74+
name: 'v1.1'
75+
}.to_json
76+
end
77+
78+
it 'returns a hash containing the information about the latest update' do
79+
expect(subject.get_update('1.0')).to include(
80+
release_notes: 'notes',
81+
zip_url: 'url',
82+
release_name: 'v1.1'
83+
)
84+
end
85+
end
86+
end
87+
end

wpxf.rb

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33
require 'fileutils'
44
require_relative 'env'
55
require 'cli/console'
6+
require 'slop'
7+
8+
Slop.parse do |o|
9+
o.on '--update', 'check for updates' do
10+
current_version = File.read('VERSION').strip
11+
12+
updater = Wpxf::GitHubUpdater.new
13+
update = updater.get_update(current_version)
14+
15+
if update.nil?
16+
puts 'No updates available'
17+
exit
18+
end
19+
20+
puts 'A new update is available!'
21+
puts
22+
puts '-- Release Notes --'
23+
puts update[:release_notes]
24+
puts
25+
puts "Downloading latest update (#{update[:release_name]})..."
26+
updater.download_and_apply_update(update[:zip_url])
27+
28+
puts 'Update finished! Make sure to run "bundle install" in the WPXF directory.'
29+
puts
30+
exit
31+
end
32+
33+
o.on '--version', 'print the version' do
34+
puts File.read('VERSION').strip
35+
exit
36+
end
37+
end
638

739
puts ' _'
840
puts ' __ _____ _ __ __| |_ __ _ __ ___ ___ ___'
@@ -31,7 +63,7 @@
3163

3264
Dir.chdir(Dir.tmpdir) do
3365
temp_directories = Dir.glob('wpxf_*')
34-
if temp_directories.length > 0
66+
unless temp_directories.empty?
3567
print '[!] '.yellow
3668
puts "#{temp_directories.length} temporary files were found that "\
3769
'appear to no longer be needed.'

0 commit comments

Comments
 (0)