chook 1.0.1.b2 → 1.1.0
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 +5 -5
- data/CHANGES.md +21 -0
- data/README.md +243 -36
- data/bin/chook-server +29 -1
- data/data/chook.conf.example +104 -0
- data/data/sample_handlers/RestAPIOperation.rb +12 -8
- data/data/sample_handlers/SmartGroupComputerMembershipChange.rb +3 -6
- data/data/sample_jsons/SmartGroupComputerMembershipChange.json +3 -1
- data/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +3 -1
- data/lib/chook/configuration.rb +20 -8
- data/lib/chook/event/handled_event.rb +15 -12
- data/lib/chook/event/handled_event/handlers.rb +136 -83
- data/lib/chook/event/handled_event_logger.rb +86 -0
- data/lib/chook/event_handling.rb +1 -0
- data/lib/chook/foundation.rb +2 -0
- data/lib/chook/procs.rb +17 -1
- data/lib/chook/server.rb +71 -74
- data/lib/chook/server/log.rb +215 -0
- data/lib/chook/server/public/css/chook.css +125 -0
- data/lib/chook/server/public/imgs/ChookLogoAlMcWhiggin.png +0 -0
- data/lib/chook/server/public/js/chook.js +127 -0
- data/lib/chook/server/public/js/logstream.js +101 -0
- data/lib/chook/server/routes.rb +45 -0
- data/lib/chook/server/routes/handle_webhook_event.rb +22 -3
- data/lib/chook/server/routes/handlers.rb +52 -0
- data/lib/chook/server/routes/home.rb +34 -1
- data/lib/chook/server/routes/log.rb +106 -0
- data/lib/chook/server/views/admin.haml +11 -0
- data/lib/chook/server/views/bak.haml +48 -0
- data/lib/chook/server/views/config.haml +15 -0
- data/lib/chook/server/views/handlers.haml +48 -0
- data/lib/chook/server/views/layout.haml +39 -0
- data/lib/chook/server/views/logstream.haml +32 -0
- data/lib/chook/server/views/sketch_admin +44 -0
- data/lib/chook/subject.rb +1 -2
- data/lib/chook/subject/smart_group.rb +6 -0
- data/lib/chook/version.rb +1 -1
- metadata +73 -18
@@ -0,0 +1,125 @@
|
|
1
|
+
@charset "UTF-8";
|
2
|
+
|
3
|
+
/* ******* General Styling ******* */
|
4
|
+
|
5
|
+
.monospaced {
|
6
|
+
font-family: "Lucida Console", Monaco, monospace;
|
7
|
+
}
|
8
|
+
|
9
|
+
|
10
|
+
/* ******* Title Header Area ******* */
|
11
|
+
|
12
|
+
.chook_title {
|
13
|
+
font-weight: bold;
|
14
|
+
font-size: 2.5em;
|
15
|
+
}
|
16
|
+
|
17
|
+
#header_version {
|
18
|
+
font-size: 0.5em;
|
19
|
+
}
|
20
|
+
|
21
|
+
#definition {
|
22
|
+
line-height: 1.6;
|
23
|
+
}
|
24
|
+
|
25
|
+
.def_pronunciation {
|
26
|
+
font-style: italic;
|
27
|
+
font-size: 1.2em;
|
28
|
+
}
|
29
|
+
|
30
|
+
.def_part_of_speech {
|
31
|
+
font-weight: bold;
|
32
|
+
}
|
33
|
+
|
34
|
+
.def_dialect {
|
35
|
+
font-style: italic;
|
36
|
+
}
|
37
|
+
|
38
|
+
.def_definition {
|
39
|
+
font-size: 1.2em;
|
40
|
+
}
|
41
|
+
|
42
|
+
/* ******* Section Label Areas ******* */
|
43
|
+
|
44
|
+
.section_label {
|
45
|
+
padding-bottom: 5px;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* ******* Live Log Section ******* */
|
49
|
+
|
50
|
+
#hide_log_btn {
|
51
|
+
display: none;
|
52
|
+
}
|
53
|
+
|
54
|
+
#logbox_div {
|
55
|
+
display: none;
|
56
|
+
}
|
57
|
+
|
58
|
+
#logbox_btns {
|
59
|
+
padding-bottom: 5px;
|
60
|
+
}
|
61
|
+
|
62
|
+
#logbox {
|
63
|
+
width: 100%;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* ******* Handlers Section ******* */
|
67
|
+
|
68
|
+
#hide_handlers_btn {
|
69
|
+
display: none;
|
70
|
+
}
|
71
|
+
|
72
|
+
#handlers_div {
|
73
|
+
display: none;
|
74
|
+
}
|
75
|
+
|
76
|
+
#handlers_table {
|
77
|
+
width: 100%;
|
78
|
+
border: 1px solid black;
|
79
|
+
border-collapse: collapse;
|
80
|
+
margin-top: 5px;
|
81
|
+
padding-bottom: 5px;
|
82
|
+
}
|
83
|
+
|
84
|
+
#handlers_table_header_row {
|
85
|
+
text-align: left;
|
86
|
+
border: 1px solid black;
|
87
|
+
border-collapse: collapse;
|
88
|
+
background-color: LightGrey;
|
89
|
+
padding-top: 4px;
|
90
|
+
padding-left: 3px;
|
91
|
+
}
|
92
|
+
|
93
|
+
.handlers_table_cell {
|
94
|
+
text-align: left;
|
95
|
+
border: 1px solid black;
|
96
|
+
border-collapse: collapse;
|
97
|
+
padding-top: 4px;
|
98
|
+
padding-left: 3px;
|
99
|
+
}
|
100
|
+
|
101
|
+
#handler_viewer_div {
|
102
|
+
display: none;
|
103
|
+
padding-top: 15px;
|
104
|
+
}
|
105
|
+
|
106
|
+
#handler_viewer {
|
107
|
+
width: 95%;
|
108
|
+
border: 3px solid black;
|
109
|
+
padding-top: 5px;
|
110
|
+
}
|
111
|
+
|
112
|
+
/* ******* Handlers Section ******* */
|
113
|
+
|
114
|
+
#hide_config_btn {
|
115
|
+
display: none;
|
116
|
+
}
|
117
|
+
|
118
|
+
#config_div {
|
119
|
+
display: none;
|
120
|
+
}
|
121
|
+
|
122
|
+
#config_viewer_div {
|
123
|
+
margin-top: 5px;
|
124
|
+
padding-bottom: 5px;
|
125
|
+
}
|
Binary file
|
@@ -0,0 +1,127 @@
|
|
1
|
+
|
2
|
+
// show the logbox
|
3
|
+
function view_log() {
|
4
|
+
document.getElementById("pause_log").checked = false
|
5
|
+
document.getElementById("logbox_div").style.display = 'block';
|
6
|
+
document.getElementById("view_log_btn").style.display = 'none';
|
7
|
+
document.getElementById("hide_log_btn").style.display = 'inline';
|
8
|
+
start_log_stream();
|
9
|
+
update_logbox();
|
10
|
+
}
|
11
|
+
|
12
|
+
// hide the logbox
|
13
|
+
function hide_log() {
|
14
|
+
document.getElementById("logbox_div").style.display = 'none';
|
15
|
+
document.getElementById("view_log_btn").style.display = 'inline';
|
16
|
+
document.getElementById("hide_log_btn").style.display = 'none';
|
17
|
+
document.getElementById("pause_log").checked = true;
|
18
|
+
}
|
19
|
+
|
20
|
+
// clear the log stream
|
21
|
+
function clear_log(){
|
22
|
+
document.getElementById("logbox").value = '';
|
23
|
+
log_source = '';
|
24
|
+
}
|
25
|
+
|
26
|
+
// change the log level
|
27
|
+
function change_log_level() {
|
28
|
+
var new_level = document.getElementById("log_level_select").value
|
29
|
+
var url = "/set_log_level/" + new_level
|
30
|
+
var xhttp = new XMLHttpRequest();
|
31
|
+
xhttp.open("PUT", url, true);
|
32
|
+
xhttp.send();
|
33
|
+
}
|
34
|
+
|
35
|
+
// reload the handlers
|
36
|
+
function reload_handlers() {
|
37
|
+
var url = '/reload_handlers';
|
38
|
+
var xhttp = new XMLHttpRequest();
|
39
|
+
xhttp.onreadystatechange = function() {
|
40
|
+
if (this.readyState == 4 && this.status == 200) {
|
41
|
+
now = new Date().toLocaleString();
|
42
|
+
document.getElementById("reloaded_notification").innerHTML = 'Reloaded at ' + now;
|
43
|
+
} else {
|
44
|
+
document.getElementById("reloaded_notification").innerHTML = 'Reload Failed.';
|
45
|
+
}
|
46
|
+
};
|
47
|
+
xhttp.open("GET", url, true);
|
48
|
+
xhttp.send();
|
49
|
+
}
|
50
|
+
|
51
|
+
// show the handler area
|
52
|
+
function view_handlers() {
|
53
|
+
document.getElementById("handlers_div").style.display = 'block';
|
54
|
+
document.getElementById("view_handlers_btn").style.display = 'none';
|
55
|
+
document.getElementById("hide_handlers_btn").style.display = 'inline';
|
56
|
+
}
|
57
|
+
|
58
|
+
// hide the handler area
|
59
|
+
function hide_handlers() {
|
60
|
+
document.getElementById("handlers_div").style.display = 'none';
|
61
|
+
document.getElementById("view_handlers_btn").style.display = 'inline';
|
62
|
+
document.getElementById("hide_handlers_btn").style.display = 'none';
|
63
|
+
}
|
64
|
+
|
65
|
+
// hide the handler editor
|
66
|
+
function hide_handler_viewer() {
|
67
|
+
document.getElementById("handler_viewer_div").style.display = 'none';
|
68
|
+
}
|
69
|
+
|
70
|
+
// show the handler editor with the selected handler code
|
71
|
+
// handler = the path to the hander fle.
|
72
|
+
function edit_handler(handler, type) {
|
73
|
+
var code = '';
|
74
|
+
var editing_filename = handler;
|
75
|
+
|
76
|
+
// new handler
|
77
|
+
if (handler == 'new_handler') {
|
78
|
+
editing_filename = new_handler_filename();
|
79
|
+
if (editing_filename == 'Name Already Taken') {
|
80
|
+
code = editing_filename;
|
81
|
+
}
|
82
|
+
document.getElementById("handler_viewer").value = code;
|
83
|
+
|
84
|
+
if (document.getElementById("add_handler_external_radio").checked) {
|
85
|
+
type = 'external';
|
86
|
+
} else {
|
87
|
+
type = 'internal';
|
88
|
+
}
|
89
|
+
|
90
|
+
// existing handler
|
91
|
+
} else {
|
92
|
+
fetch_handler_code(handler) ;
|
93
|
+
}
|
94
|
+
var now_editing = editing_filename + ' (' + type + ')'
|
95
|
+
document.getElementById("currently_viewing_filename").innerHTML = now_editing;
|
96
|
+
document.getElementById("handler_viewer_div").style.display = 'block';
|
97
|
+
}
|
98
|
+
|
99
|
+
// get the code for an existing handler into the editor
|
100
|
+
function fetch_handler_code(handler) {
|
101
|
+
var editor = document.getElementById("handler_viewer");
|
102
|
+
var url = '/handler_code/' + handler
|
103
|
+
var xhttp = new XMLHttpRequest();
|
104
|
+
xhttp.onreadystatechange = function() {
|
105
|
+
if (this.readyState == 4 && this.status == 200) {
|
106
|
+
editor.value = xhttp.responseText;
|
107
|
+
} else {
|
108
|
+
editor.value = 'ERROR: File Not Found';
|
109
|
+
}
|
110
|
+
};
|
111
|
+
xhttp.open("GET", url, true);
|
112
|
+
xhttp.send();
|
113
|
+
}
|
114
|
+
|
115
|
+
// show the config area
|
116
|
+
function view_config() {
|
117
|
+
document.getElementById("config_div").style.display = 'block';
|
118
|
+
document.getElementById("view_config_btn").style.display = 'none';
|
119
|
+
document.getElementById("hide_config_btn").style.display = 'inline';
|
120
|
+
}
|
121
|
+
|
122
|
+
// hide the config area
|
123
|
+
function hide_config() {
|
124
|
+
document.getElementById("config_div").style.display = 'none';
|
125
|
+
document.getElementById("view_config_btn").style.display = 'inline';
|
126
|
+
document.getElementById("hide_config_btn").style.display = 'none';
|
127
|
+
}
|
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
// Vars
|
3
|
+
//////////////////////////////////
|
4
|
+
|
5
|
+
// the url that will provide the stream
|
6
|
+
var log_stream_url = '/subscribe_to_log_stream';
|
7
|
+
|
8
|
+
// the EventSource that will get events from the url
|
9
|
+
var log_source
|
10
|
+
|
11
|
+
// the log box on the info page
|
12
|
+
var logbox
|
13
|
+
|
14
|
+
// the checkbox to pause updating the log box
|
15
|
+
var pause_ckbx
|
16
|
+
|
17
|
+
// data from the log gets added to this string
|
18
|
+
// but its only written to the log box if we
|
19
|
+
// aren't paused.
|
20
|
+
var log_data
|
21
|
+
|
22
|
+
var new_log_level_regex = /Log level changed, now: (.*)$/;
|
23
|
+
|
24
|
+
// update the text in the log box unless the
|
25
|
+
// pause checkbox is checked
|
26
|
+
function update_logbox() {
|
27
|
+
if (pause_ckbx.checked) { return; }
|
28
|
+
logbox.value = log_data;
|
29
|
+
logbox.scrollTop = logbox.scrollHeight;
|
30
|
+
}
|
31
|
+
|
32
|
+
// start the stream
|
33
|
+
function start_log_stream() {
|
34
|
+
// always update the log level
|
35
|
+
get_current_log_level();
|
36
|
+
// return if already started
|
37
|
+
if (typeof(log_source) != "undefined") { return; }
|
38
|
+
|
39
|
+
logbox = document.getElementById("logbox");
|
40
|
+
pause_ckbx = document.getElementById("pause_log");
|
41
|
+
|
42
|
+
log_data = logbox.value;
|
43
|
+
log_source = new EventSource(log_stream_url);
|
44
|
+
|
45
|
+
// add incoming lines of data from the server
|
46
|
+
// to the in-memory cache
|
47
|
+
log_source.onmessage = function (event) {
|
48
|
+
var msg = event.data;
|
49
|
+
log_data = log_data + msg + "\n";
|
50
|
+
update_logbox();
|
51
|
+
var match = new_log_level_regex.exec(msg);
|
52
|
+
if (match) { update_log_level_selector(match[1]); }
|
53
|
+
};
|
54
|
+
|
55
|
+
// close the streams when client pages are closed.
|
56
|
+
// The server will see that the streams are closed
|
57
|
+
// and will remove the registrations as needed.
|
58
|
+
window.onbeforeunload = function() {
|
59
|
+
log_source.close();
|
60
|
+
return null;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
// update the selector with the current log level from the server
|
65
|
+
function get_current_log_level() {
|
66
|
+
var url = '/current_log_level';
|
67
|
+
var xhttp = new XMLHttpRequest();
|
68
|
+
|
69
|
+
xhttp.onreadystatechange = function() {
|
70
|
+
if (this.readyState == 4 && this.status == 200) {
|
71
|
+
update_log_level_selector(xhttp.responseText);
|
72
|
+
}
|
73
|
+
};
|
74
|
+
|
75
|
+
xhttp.open("GET", url, true);
|
76
|
+
xhttp.send();
|
77
|
+
}
|
78
|
+
|
79
|
+
function update_log_level_selector(new_level) {
|
80
|
+
var new_idx;
|
81
|
+
switch(new_level) {
|
82
|
+
case 'fatal':
|
83
|
+
new_idx = 0;
|
84
|
+
break;
|
85
|
+
case 'error':
|
86
|
+
new_idx = 1;
|
87
|
+
break;
|
88
|
+
case 'warn':
|
89
|
+
new_idx = 2;
|
90
|
+
break;
|
91
|
+
case 'info':
|
92
|
+
new_idx = 3;
|
93
|
+
break;
|
94
|
+
case 'debug':
|
95
|
+
new_idx = 4;
|
96
|
+
break;
|
97
|
+
default:
|
98
|
+
new_idx = null;
|
99
|
+
}
|
100
|
+
document.getElementById("log_level_select").selectedIndex = new_idx;
|
101
|
+
}
|
data/lib/chook/server/routes.rb
CHANGED
@@ -23,5 +23,50 @@
|
|
23
23
|
###
|
24
24
|
###
|
25
25
|
|
26
|
+
module Chook
|
27
|
+
|
28
|
+
# the server
|
29
|
+
class Server < Sinatra::Base
|
30
|
+
|
31
|
+
# These two helpers let us decude which routes need
|
32
|
+
# http basic auth and which don't
|
33
|
+
#
|
34
|
+
# To protect a route, put `protected!` as the
|
35
|
+
# first line of code in the route.
|
36
|
+
#
|
37
|
+
# See http://sinatrarb.com/faq.html#auth
|
38
|
+
#
|
39
|
+
helpers do
|
40
|
+
def protected!
|
41
|
+
# don't protect if user isn't defined
|
42
|
+
return unless Chook.config.webhooks_user
|
43
|
+
|
44
|
+
return if authorized?
|
45
|
+
headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
|
46
|
+
halt 401, "Not authorized\n"
|
47
|
+
end
|
48
|
+
|
49
|
+
def authorized?
|
50
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
51
|
+
@auth.provided? && \
|
52
|
+
@auth.basic? && \
|
53
|
+
@auth.credentials && \
|
54
|
+
@auth.credentials == [Chook.config.webhooks_user, Chook::Server.webhooks_user_pw]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# log errors in production (in dev, they go to stdout and the browser)
|
59
|
+
error do
|
60
|
+
logger.error "ERROR: #{env['sinatra.error'].message}"
|
61
|
+
env['sinatra.error'].backtrace.each { |l| logger.error "..#{l}" }
|
62
|
+
500
|
63
|
+
end
|
64
|
+
|
65
|
+
end # server
|
66
|
+
|
67
|
+
end # Chook
|
68
|
+
|
26
69
|
require 'chook/server/routes/home'
|
27
70
|
require 'chook/server/routes/handle_webhook_event'
|
71
|
+
require 'chook/server/routes/handlers'
|
72
|
+
require 'chook/server/routes/log'
|
@@ -29,9 +29,28 @@ module Chook
|
|
29
29
|
class Server < Sinatra::Base
|
30
30
|
|
31
31
|
post '/handle_webhook_event' do
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
# enforce http basic auth if needed
|
33
|
+
protected!
|
34
|
+
|
35
|
+
# rewind to ensure read-pointer is at the start
|
36
|
+
request.body.rewind #
|
37
|
+
raw_json = request.body.read
|
38
|
+
|
39
|
+
event = Chook::HandledEvent.parse_event raw_json
|
40
|
+
if event.nil?
|
41
|
+
logger.error "Empty JSON from #{request.ip}"
|
42
|
+
result = 400
|
43
|
+
else
|
44
|
+
|
45
|
+
event.logger.info "START From #{request.ip}, WebHook '#{event.webhook_name}' (id: #{event.webhook_id})"
|
46
|
+
|
47
|
+
event.logger.debug "JSON: #{raw_json}"
|
48
|
+
|
49
|
+
result = event.handle
|
50
|
+
|
51
|
+
event.logger.info "END #{result}"
|
52
|
+
end
|
53
|
+
result
|
35
54
|
end # post
|
36
55
|
|
37
56
|
end # class
|
@@ -0,0 +1,52 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
module Chook
|
27
|
+
|
28
|
+
# see server.rb
|
29
|
+
class Server < Sinatra::Base
|
30
|
+
|
31
|
+
# reload the handlers
|
32
|
+
get '/reload_handlers' do
|
33
|
+
protected!
|
34
|
+
logger.info 'Reloading handlers'
|
35
|
+
Chook::HandledEvent::Handlers.load_handlers reload: true
|
36
|
+
'Handlers reloaded'
|
37
|
+
end # get /
|
38
|
+
|
39
|
+
# used by javascript to fetch the content of a handler
|
40
|
+
get '/handler_code/:file' do
|
41
|
+
protected!
|
42
|
+
file = Chook.config.handler_dir + params[:file]
|
43
|
+
if file.file?
|
44
|
+
body file.read
|
45
|
+
else
|
46
|
+
404
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class
|
51
|
+
|
52
|
+
end # module
|