haplo 2.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
})();
|