haplo 2.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.txt +17 -0
- data/bin/haplo-plugin +3 -0
- data/haplo.gemspec +18 -0
- data/lib/CertificateBundle.pem +3952 -0
- data/lib/auth.rb +168 -0
- data/lib/check.rb +60 -0
- data/lib/custom.rb +73 -0
- data/lib/haplo-templates.jar +0 -0
- data/lib/hmac.rb +12 -0
- data/lib/js.jar +0 -0
- data/lib/js_min.js +38 -0
- data/lib/js_syntax_test.js +88 -0
- data/lib/jshint.js +4359 -0
- data/lib/local_config.rb +28 -0
- data/lib/manifest.rb +44 -0
- data/lib/minimise.rb +68 -0
- data/lib/misc.rb +8 -0
- data/lib/new_plugin.rb +88 -0
- data/lib/notifications.rb +89 -0
- data/lib/packing.rb +62 -0
- data/lib/plugin.rb +227 -0
- data/lib/plugin_tool.rb +197 -0
- data/lib/run.rb +67 -0
- data/lib/schema_requirements.rb +63 -0
- data/lib/server.rb +143 -0
- data/lib/syntax_checking.rb +120 -0
- data/lib/uglifyjs/parse-js.js +1342 -0
- data/lib/uglifyjs/process.js +2011 -0
- data/lib/uglifyjs/squeeze-more.js +69 -0
- data/lib/usage.txt +81 -0
- data/lib/version.txt +1 -0
- data/lib/watchers.rb +39 -0
- metadata +76 -0
data/lib/auth.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
@@keys_pathname = "#{Dir.getwd}/.server.json"
|
5
|
+
|
6
|
+
# ---------------------------------------------------------------------------------------------------------
|
7
|
+
|
8
|
+
def self.setup_auth(options)
|
9
|
+
keys = load_keys_file()
|
10
|
+
server = keys['default']
|
11
|
+
if options.server_substring
|
12
|
+
server = select_server(keys, options.server_substring)
|
13
|
+
end_on_error "No server found for substring '#{options.server_substring}'" unless server
|
14
|
+
end
|
15
|
+
key = keys['keys'][server]
|
16
|
+
if key
|
17
|
+
hostname, port, url_base = parse_hostname_with_port(server)
|
18
|
+
set_server(hostname, port, key)
|
19
|
+
puts "Application: #{url_base}"
|
20
|
+
else
|
21
|
+
end_on_error "No server authorised. Run haplo-plugin auth SERVER_NAME"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# ---------------------------------------------------------------------------------------------------------
|
26
|
+
|
27
|
+
def self.cmd_server(options)
|
28
|
+
end_on_error "No server name substring given on command line" if options.args.empty?
|
29
|
+
keys = load_keys_file()
|
30
|
+
server = select_server(keys, options.args.first)
|
31
|
+
end_on_error "No server found for substring '#{options.args.first}" unless server
|
32
|
+
keys['default'] = server
|
33
|
+
puts "Selected server #{server}"
|
34
|
+
save_keys_file(keys)
|
35
|
+
end
|
36
|
+
|
37
|
+
# ---------------------------------------------------------------------------------------------------------
|
38
|
+
|
39
|
+
def self.cmd_auth(options)
|
40
|
+
end_on_error "No hostname given on command line" if options.args.empty?
|
41
|
+
hostname, port, url_base, server_name = parse_hostname_with_port(options.args.first)
|
42
|
+
|
43
|
+
keys = load_keys_file()
|
44
|
+
if keys['keys'].has_key?(server_name) && !options.force
|
45
|
+
puts
|
46
|
+
puts "Already authorised with #{server_name}"
|
47
|
+
puts "Use the --force argument to reauthorise with the server."
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
set_server(hostname, port, nil)
|
52
|
+
check_for_certificate_file()
|
53
|
+
http = get_http()
|
54
|
+
|
55
|
+
this_hostname = java.net.InetAddress.getLocalHost().getHostName() || "unknown"
|
56
|
+
|
57
|
+
puts "Requesting token from #{url_base} ..."
|
58
|
+
start_auth_path = "/api/plugin-tool-auth/start-auth?name=#{URI.encode(this_hostname)}"
|
59
|
+
request = Net::HTTP::Get.new(start_auth_path)
|
60
|
+
setup_request(request)
|
61
|
+
token = nil
|
62
|
+
begin
|
63
|
+
response = http.request(request)
|
64
|
+
end_on_error "Server returned an error. Check hostname and port." unless response.code == "200"
|
65
|
+
parsed_json = JSON.parse(response.body)
|
66
|
+
token = parsed_json['token']
|
67
|
+
end_on_error "Server doesn't look like a Haplo server with plugin debugging enabled" unless ((parsed_json['Haplo'] == 'plugin-tool-auth') || (parsed_json['ONEIS'] == 'plugin-tool-auth')) && token
|
68
|
+
rescue => e
|
69
|
+
end_on_error "Failed to start authorisation process. Check hostname and port."
|
70
|
+
end
|
71
|
+
|
72
|
+
# Check token looks OK so we don't form dodgy URLs
|
73
|
+
end_on_error "Bad token" unless token =~ /\A[a-z0-9A-Z_-]+\z/
|
74
|
+
|
75
|
+
user_url = "#{url_base}/do/plugin-tool-auth/create/#{token}"
|
76
|
+
poll_path = "/api/plugin-tool-auth/poll/#{token}"
|
77
|
+
|
78
|
+
puts
|
79
|
+
if java.lang.System.getProperty("os.name") == 'Mac OS X'
|
80
|
+
puts "Attempting to open the following URL in your browser."
|
81
|
+
puts "If the browser does not open, please visit this URL in your browser."
|
82
|
+
system "open #{user_url}"
|
83
|
+
else
|
84
|
+
puts "Please visit this URL in your browser, and authenticate if necessary."
|
85
|
+
end
|
86
|
+
puts " #{user_url}"
|
87
|
+
puts
|
88
|
+
|
89
|
+
# Poll for a few minutes, waiting for the user to authenticate
|
90
|
+
puts "Waiting for server to authorise..."
|
91
|
+
poll_count = 0
|
92
|
+
key = nil
|
93
|
+
while poll_count < 60 && !key
|
94
|
+
delay = if poll_count < 10
|
95
|
+
2
|
96
|
+
elsif poll_count < 20
|
97
|
+
4
|
98
|
+
else
|
99
|
+
8
|
100
|
+
end
|
101
|
+
sleep delay
|
102
|
+
begin
|
103
|
+
request = Net::HTTP::Get.new(poll_path)
|
104
|
+
setup_request(request)
|
105
|
+
response = http.request(request)
|
106
|
+
parsed_json = JSON.parse(response.body)
|
107
|
+
case parsed_json['status']
|
108
|
+
when 'wait'
|
109
|
+
# poll again
|
110
|
+
when 'available'
|
111
|
+
key = parsed_json['key']
|
112
|
+
else
|
113
|
+
end_on_error "Authorisation process failed."
|
114
|
+
end
|
115
|
+
rescue => e
|
116
|
+
end_on_error "Error communicating with server"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
finish_with_connection()
|
120
|
+
|
121
|
+
end_on_error "Didn't managed to authorise with server." unless key
|
122
|
+
|
123
|
+
puts "Successfully authorised with server."
|
124
|
+
|
125
|
+
keys['default'] = server_name
|
126
|
+
keys['keys'][server_name] = key
|
127
|
+
save_keys_file(keys)
|
128
|
+
|
129
|
+
puts
|
130
|
+
puts "Key stored in #{@@keys_pathname}"
|
131
|
+
puts "#{server_name} selected as default server."
|
132
|
+
end
|
133
|
+
|
134
|
+
# ---------------------------------------------------------------------------------------------------------
|
135
|
+
|
136
|
+
def self.parse_hostname_with_port(hostname_with_port)
|
137
|
+
hostname_with_port = hostname_with_port.downcase.strip
|
138
|
+
unless hostname_with_port =~ /\A(https?:\/\/)?([a-z0-9\.-]+)(:(\d+))?/i
|
139
|
+
end_on_error "Bad hostname #{hostname_with_port}"
|
140
|
+
end
|
141
|
+
hostname = $2
|
142
|
+
port = $4 ? $4.to_i : 443
|
143
|
+
server_name = "#{hostname}#{(port != 443) ? ":#{port}" : ''}"
|
144
|
+
[hostname, port, "https://#{server_name}", server_name]
|
145
|
+
end
|
146
|
+
|
147
|
+
# ---------------------------------------------------------------------------------------------------------
|
148
|
+
|
149
|
+
def self.load_keys_file
|
150
|
+
if File.exist?(@@keys_pathname)
|
151
|
+
File.open(@@keys_pathname) { |f| JSON.parse(f.read) }
|
152
|
+
else
|
153
|
+
{"_" => "Contains server keys. DO NOT COMMIT TO SOURCE CONTROL.", "default" => nil, "keys" => {}}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.save_keys_file(keys)
|
158
|
+
pn = "#{@@keys_pathname}.n"
|
159
|
+
File.open(pn, "w") { |f| f.write(JSON.pretty_generate(keys)) }
|
160
|
+
File.rename(pn, @@keys_pathname)
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.select_server(keys, substring)
|
164
|
+
s = substring.downcase.strip
|
165
|
+
keys['keys'].keys.sort { |a,b| (a.length == b.length) ? (a <=> b) : (a.length <=> b.length) } .find { |a| a.include? s }
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
data/lib/check.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
def self.check_plugins(plugins)
|
5
|
+
init_syntax_checking
|
6
|
+
@@check_report = ''
|
7
|
+
@@check_ok = true
|
8
|
+
@@check_warn = false
|
9
|
+
plugins.each { |p| check_plugin(p) }
|
10
|
+
if @@check_warn || !(@@check_ok)
|
11
|
+
puts "\nFILES WITH ERRORS"
|
12
|
+
puts @@check_report
|
13
|
+
end
|
14
|
+
# Output the verdict
|
15
|
+
puts
|
16
|
+
if @@check_ok && !@@check_warn
|
17
|
+
puts "PASSED"
|
18
|
+
elsif @@check_warn
|
19
|
+
puts "PASSED WITH WARNINGS"
|
20
|
+
else
|
21
|
+
puts "FAILED"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.check_plugin(plugin)
|
27
|
+
plugin_dir = plugin.plugin_dir
|
28
|
+
STDOUT.write(plugin.name+" ")
|
29
|
+
Dir.glob("#{plugin_dir}/**/*").each do |pathname|
|
30
|
+
next unless File.file?(pathname)
|
31
|
+
next if plugin.exclude_files_from_syntax_check.include?(pathname)
|
32
|
+
plugin_relative_name = pathname[plugin_dir.length+1, pathname.length]
|
33
|
+
if pathname =~ /\.(js|hsvt)\z/i
|
34
|
+
STDOUT.write("."); STDOUT.flush
|
35
|
+
# Check JavaScript
|
36
|
+
report = syntax_check_one_file(plugin, plugin_relative_name)
|
37
|
+
if report == nil
|
38
|
+
check_file_result(plugin, plugin_relative_name, :OK)
|
39
|
+
else
|
40
|
+
puts "\n**** #{plugin_relative_name} has errors:\n#{report}\n"
|
41
|
+
check_file_result(plugin, plugin_relative_name, (plugin_relative_name =~ /\Ajs\//) ? :FAIL : :WARN)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
# TODO: Checks for other file types, including the plugin.json
|
45
|
+
check_file_result(plugin, plugin_relative_name, :OK)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
STDOUT.write("\n"); STDOUT.flush
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.check_file_result(plugin, name, result)
|
52
|
+
unless result == :OK
|
53
|
+
@@check_report << " #{plugin.plugin_dir}/#{name}: #{result}\n"
|
54
|
+
end
|
55
|
+
@@check_ok = false if result == :FAIL
|
56
|
+
@@check_warn = true if result == :WARN
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
data/lib/custom.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
LOCAL_CUSTOM_BEHAVIOUR_FILENAME = "server.behaviour.rb"
|
5
|
+
|
6
|
+
# Digests of trusted code are stored outside the source code repo, so it can't be written by the repo contents
|
7
|
+
TRUSTED_CODE_DIGESTS_FILENAME = "~/.haplo-plugin-tool-trusted.json"
|
8
|
+
|
9
|
+
class CustomBehaviour
|
10
|
+
def start(plugins, command, options, is_local_command)
|
11
|
+
end
|
12
|
+
def server_ready(plugins, command, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
@@custom = CustomBehaviour.new
|
17
|
+
|
18
|
+
def self.set_custom_behaviour(custom)
|
19
|
+
@@custom = custom
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.custom_behaviour
|
23
|
+
@@custom
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.try_load_custom
|
27
|
+
return unless File.exist?(LOCAL_CUSTOM_BEHAVIOUR_FILENAME)
|
28
|
+
|
29
|
+
trusted_code = nil
|
30
|
+
untrusted_code = File.open(LOCAL_CUSTOM_BEHAVIOUR_FILENAME) { |f| f.read }
|
31
|
+
untrusted_code_digest = Digest::SHA256.hexdigest(untrusted_code)
|
32
|
+
|
33
|
+
trusted_code_digests = {"trust" => []}
|
34
|
+
trusted_code_filename = File.expand_path(TRUSTED_CODE_DIGESTS_FILENAME)
|
35
|
+
if File.exist?(trusted_code_filename)
|
36
|
+
trusted_code_digests = JSON.parse(File.open(trusted_code_filename) { |f| f.read })
|
37
|
+
end
|
38
|
+
|
39
|
+
unless trusted_code_digests["trust"].include?(untrusted_code_digest)
|
40
|
+
# Make sure the user wants to run this code. Otherwise running the plugin tool in a repo you've just
|
41
|
+
# downloaded could unexpectedly execute code on your local machine.
|
42
|
+
if ARGV.length == 2 && ARGV[0] == 'trust' && ARGV[1] =~ /\A[0-9a-z]{64}\z/ && ARGV[1] == untrusted_code_digest
|
43
|
+
trusted_code_digests["trust"].push(untrusted_code_digest)
|
44
|
+
File.open(trusted_code_filename,"w") { |f| f.write JSON.pretty_generate(trusted_code_digests) }
|
45
|
+
puts "Stored trust for #{LOCAL_CUSTOM_BEHAVIOUR_FILENAME} with contents #{untrusted_code_digest}."
|
46
|
+
exit 0
|
47
|
+
else
|
48
|
+
puts
|
49
|
+
puts "-------------------------------------------------------------------------------------------"
|
50
|
+
puts " Do you trust the code in #{LOCAL_CUSTOM_BEHAVIOUR_FILENAME} to be run every time you run the"
|
51
|
+
puts " plugin tool? If yes, run"
|
52
|
+
puts " haplo-plugin trust #{untrusted_code_digest}"
|
53
|
+
puts " to permanently trust this version of #{LOCAL_CUSTOM_BEHAVIOUR_FILENAME}"
|
54
|
+
puts "-------------------------------------------------------------------------------------------"
|
55
|
+
puts
|
56
|
+
PluginTool.beep
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if ARGV.length > 0 && ARGV[0] == "trust"
|
62
|
+
puts "Unexpected trust command."
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
|
66
|
+
# User trusts the code, run it
|
67
|
+
# There is a race condition here, but we're trying to protect against code in repositories, not
|
68
|
+
# against software running on the local machine.
|
69
|
+
load LOCAL_CUSTOM_BEHAVIOUR_FILENAME
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
Binary file
|
data/lib/hmac.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module HMAC
|
3
|
+
module SHA1
|
4
|
+
def self.sign(key, message)
|
5
|
+
mac = javax.crypto.Mac.getInstance("HmacSHA1")
|
6
|
+
mac.init(javax.crypto.spec.SecretKeySpec.new(key.to_java_bytes, "HmacSHA1"))
|
7
|
+
result = mac.doFinal(message.to_java_bytes)
|
8
|
+
String.from_java_bytes(result).unpack('H*').join
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
data/lib/js.jar
ADDED
Binary file
|
data/lib/js_min.js
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
// Emulate enough of CommonJS to load unmodified UglifyJS files
|
3
|
+
var exports = {};
|
4
|
+
function require() {
|
5
|
+
return exports;
|
6
|
+
}
|
7
|
+
|
8
|
+
// Enough compatibility with JavaScript 1.8
|
9
|
+
// Copied from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Reduce
|
10
|
+
if(!Array.prototype.reduce) {
|
11
|
+
Array.prototype.reduce = function reduce(accumlator){
|
12
|
+
var i, l = this.length, curr;
|
13
|
+
if(typeof accumlator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception."
|
14
|
+
throw new TypeError("First argument is not callable");
|
15
|
+
if((l == 0 || l === null) && (arguments.length <= 1))// == on purpose to test 0 and false.
|
16
|
+
throw new TypeError("Array length is 0 and no second argument");
|
17
|
+
if(arguments.length <= 1){
|
18
|
+
curr = this[0]; // Increase i to start searching the secondly defined element in the array
|
19
|
+
i = 1; // start accumulating at the second element
|
20
|
+
} else {
|
21
|
+
curr = arguments[1];
|
22
|
+
}
|
23
|
+
for(i = i || 0 ; i < l ; ++i){
|
24
|
+
if(i in this)
|
25
|
+
curr = accumlator.call(undefined, curr, this[i], i, this);
|
26
|
+
}
|
27
|
+
return curr;
|
28
|
+
};
|
29
|
+
}
|
30
|
+
|
31
|
+
// Function to call from the Ruby PluginTool::Minimiser#process function
|
32
|
+
function js_min(orig_code) {
|
33
|
+
// usage from https://github.com/mishoo/UglifyJS
|
34
|
+
var ast = jsp.parse(orig_code); // parse code and get the initial AST
|
35
|
+
ast = exports.ast_mangle(ast); // get a new AST with mangled names
|
36
|
+
ast = exports.ast_squeeze(ast); // get an AST with compression optimizations
|
37
|
+
return exports.gen_code(ast); // compressed code here
|
38
|
+
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
(function() {
|
3
|
+
var root = this;
|
4
|
+
|
5
|
+
// Options for the syntax checking
|
6
|
+
|
7
|
+
var opts = function() {
|
8
|
+
return {
|
9
|
+
asi: false,
|
10
|
+
bitwise: false,
|
11
|
+
boss: false,
|
12
|
+
curly: true,
|
13
|
+
debug: false,
|
14
|
+
devel: false,
|
15
|
+
eqeqeq: false,
|
16
|
+
evil: false,
|
17
|
+
forin: false,
|
18
|
+
immed: false,
|
19
|
+
laxbreak: false,
|
20
|
+
newcap: true,
|
21
|
+
noarg: true,
|
22
|
+
noempty: false,
|
23
|
+
nonew: true,
|
24
|
+
nomen: false,
|
25
|
+
onevar: false,
|
26
|
+
plusplus: false,
|
27
|
+
regexp: false,
|
28
|
+
undef: true,
|
29
|
+
sub: true,
|
30
|
+
strict: false,
|
31
|
+
white: false
|
32
|
+
};
|
33
|
+
};
|
34
|
+
|
35
|
+
// Options
|
36
|
+
var optionsServer = opts();
|
37
|
+
var optionsBrowser = opts();
|
38
|
+
optionsBrowser.browser = true;
|
39
|
+
|
40
|
+
// Predefined globals
|
41
|
+
var globalsServer = [
|
42
|
+
'O',
|
43
|
+
'SCHEMA', 'TYPE', 'ATTR', 'ALIASED_ATTR', 'QUAL', 'LABEL', 'GROUP',
|
44
|
+
'HTTP', 'DBTime',
|
45
|
+
'console', 'JSON',
|
46
|
+
'_', 'Handlebars', 'oForms', 'moment', 'XDate'
|
47
|
+
];
|
48
|
+
var globalsBrowser = ['Haplo', 'ONEIS', 'jQuery', '_'];
|
49
|
+
var globalsTest = globalsServer.concat('T');
|
50
|
+
|
51
|
+
// Set globals
|
52
|
+
root.syntax_tester_globals = function(string) {
|
53
|
+
globals = eval("("+string+")");
|
54
|
+
};
|
55
|
+
|
56
|
+
// Syntax tester function
|
57
|
+
root.syntax_tester = function(source, kind, extraGlobals) {
|
58
|
+
var globalList;
|
59
|
+
switch(kind) {
|
60
|
+
case "js": globalList = globalsServer; break;
|
61
|
+
case "static": globalList = globalsBrowser; break;
|
62
|
+
case "test": globalList = globalsTest; break;
|
63
|
+
}
|
64
|
+
if(!globalList) { return "Wrong kind of file"; }
|
65
|
+
var globals = {}, addGlobal = function(g) { globals[g] = false; };
|
66
|
+
globalList.forEach(addGlobal);
|
67
|
+
if(extraGlobals) {
|
68
|
+
JSON.parse(extraGlobals).forEach(addGlobal);
|
69
|
+
}
|
70
|
+
var result = JSHINT(source,
|
71
|
+
(kind !== 'static') ? optionsServer : optionsBrowser,
|
72
|
+
globals
|
73
|
+
);
|
74
|
+
if(result == true) { return null; } // success
|
75
|
+
// Errors - compile a report, can't use the default one as it's HTML
|
76
|
+
var data = JSHINT.data();
|
77
|
+
var errors = data.errors;
|
78
|
+
var report = '';
|
79
|
+
for(var e = 0; e < errors.length; e++) {
|
80
|
+
var err = errors[e];
|
81
|
+
if(err !== null && err !== undefined) { // oddly it will do that
|
82
|
+
report += "line "+err.line+": "+err.reason+"\n "+err.evidence+"\n";
|
83
|
+
}
|
84
|
+
}
|
85
|
+
return (report == '') ? null : report;
|
86
|
+
};
|
87
|
+
|
88
|
+
})();
|