conjur-asset-ui 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/.git-hooks/pre_commit/ensure_livescript_compiled.rb +31 -0
  3. data/.git-hooks/pre_commit/trailing_whitespace.rb +26 -0
  4. data/.gitignore +20 -0
  5. data/.overcommit.yml +5 -0
  6. data/.project +18 -0
  7. data/CHANGELOG.md +3 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +41 -0
  11. data/Rakefile +3 -0
  12. data/compile_ls +6 -0
  13. data/conjur-asset-ui.gemspec +37 -0
  14. data/lib/conjur/command/ui.rb +46 -0
  15. data/lib/conjur/webserver/api_proxy.rb +94 -0
  16. data/lib/conjur/webserver/authorize.rb +28 -0
  17. data/lib/conjur/webserver/conjur_info.rb +33 -0
  18. data/lib/conjur/webserver/home.rb +42 -0
  19. data/lib/conjur/webserver/login.rb +57 -0
  20. data/lib/conjur/webserver/renderer.rb +34 -0
  21. data/lib/conjur/webserver/server.rb +113 -0
  22. data/lib/conjur-asset-ui-version.rb +7 -0
  23. data/lib/conjur-asset-ui.rb +7 -0
  24. data/livescript/views/audit.ls +136 -0
  25. data/public/_client_code.html +42 -0
  26. data/public/_client_libs.html +24 -0
  27. data/public/css/bootstrap.css +7 -0
  28. data/public/css/styles.less +461 -0
  29. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  30. data/public/fonts/glyphicons-halflings-regular.svg +229 -0
  31. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  32. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  33. data/public/images/conjur-logo.svg +26 -0
  34. data/public/images/icon-client-pc.svg +12 -0
  35. data/public/images/icon-environment.png +0 -0
  36. data/public/images/icon-person.svg +12 -0
  37. data/public/images/icon-policy.png +0 -0
  38. data/public/images/icon-resource.png +0 -0
  39. data/public/images/icon-service-dots.svg +13 -0
  40. data/public/images/icon-variable.png +0 -0
  41. data/public/index.html.erb +62 -0
  42. data/public/js/init.js +107 -0
  43. data/public/js/lib/JSXTransformer.js +10862 -0
  44. data/public/js/lib/async.js +958 -0
  45. data/public/js/lib/backbone.js +2 -0
  46. data/public/js/lib/bootstrap.js +6 -0
  47. data/public/js/lib/date.extensions.js +141 -0
  48. data/public/js/lib/less.js +16 -0
  49. data/public/js/lib/moment.js +7768 -0
  50. data/public/js/lib/pace.js +2 -0
  51. data/public/js/lib/prelude-browser-min.js +1 -0
  52. data/public/js/lib/react-bootstrap.js +5346 -0
  53. data/public/js/lib/react-bootstrap.min.js +4 -0
  54. data/public/js/lib/sorted-set.no-require.js +1170 -0
  55. data/public/js/lib/sorted-set.no-require.js.txt +6 -0
  56. data/public/js/lib/underscore-min.js +6 -0
  57. data/public/js/lib/underscore.string.min.js +1 -0
  58. data/public/js/main.js +57 -0
  59. data/public/js/models/groupRecord.js +70 -0
  60. data/public/js/models/hostRecord.js +55 -0
  61. data/public/js/models/layerRecord.js +77 -0
  62. data/public/js/models/namespace.js +10 -0
  63. data/public/js/models/policyList.js +14 -0
  64. data/public/js/models/policyRecord.js +54 -0
  65. data/public/js/models/record.js +85 -0
  66. data/public/js/models/resourceList.js +69 -0
  67. data/public/js/models/userList.js +20 -0
  68. data/public/js/models/userRecord.js +70 -0
  69. data/public/js/models/variableList.js +16 -0
  70. data/public/js/models/variableRecord.js +73 -0
  71. data/public/js/routers.js +205 -0
  72. data/public/js/views/annotations.js +36 -0
  73. data/public/js/views/audit.js +363 -0
  74. data/public/js/views/dashboard.js +67 -0
  75. data/public/js/views/generic.js +115 -0
  76. data/public/js/views/group.js +61 -0
  77. data/public/js/views/groups.js +30 -0
  78. data/public/js/views/host.js +64 -0
  79. data/public/js/views/hosts.js +30 -0
  80. data/public/js/views/layer.js +92 -0
  81. data/public/js/views/layers.js +30 -0
  82. data/public/js/views/mixins/search.js +15 -0
  83. data/public/js/views/mixins/tabs.js +114 -0
  84. data/public/js/views/namespaces.js +40 -0
  85. data/public/js/views/navSearch.js +25 -0
  86. data/public/js/views/owned.js +178 -0
  87. data/public/js/views/permissions.js +188 -0
  88. data/public/js/views/policies.js +28 -0
  89. data/public/js/views/policy.js +43 -0
  90. data/public/js/views/resource.js +39 -0
  91. data/public/js/views/role.js +41 -0
  92. data/public/js/views/searchResults.js +145 -0
  93. data/public/js/views/time.js +14 -0
  94. data/public/js/views/user.js +68 -0
  95. data/public/js/views/users.js +31 -0
  96. data/public/js/views/variable.js +70 -0
  97. data/public/js/views/variables.js +30 -0
  98. data/spec/javascripts/helpers/.gitkeep +0 -0
  99. data/spec/javascripts/support/jasmine.yml +112 -0
  100. data/spec/javascripts/support/jasmine_helper.rb +22 -0
  101. data/spec/javascripts/support/run.html.erb +23 -0
  102. data/spec/javascripts/views/AuditSpec.js +22 -0
  103. data/spec/javascripts/views/AuditSpec.ls +18 -0
  104. data/vendor/prelude-ls/.gitignore +2 -0
  105. data/vendor/prelude-ls/.travis.yml +3 -0
  106. data/vendor/prelude-ls/CHANGELOG.md +81 -0
  107. data/vendor/prelude-ls/LICENSE +22 -0
  108. data/vendor/prelude-ls/Makefile +50 -0
  109. data/vendor/prelude-ls/README.md +15 -0
  110. data/vendor/prelude-ls/browser/prelude-browser-min.js +1 -0
  111. data/vendor/prelude-ls/browser/prelude-browser.js +1172 -0
  112. data/vendor/prelude-ls/lib/Func.js +40 -0
  113. data/vendor/prelude-ls/lib/List.js +602 -0
  114. data/vendor/prelude-ls/lib/Num.js +129 -0
  115. data/vendor/prelude-ls/lib/Obj.js +153 -0
  116. data/vendor/prelude-ls/lib/Str.js +68 -0
  117. data/vendor/prelude-ls/lib/index.js +164 -0
  118. data/vendor/prelude-ls/package.json +50 -0
  119. data/vendor/prelude-ls/package.ls +46 -0
  120. data/vendor/prelude-ls/src/Func.ls +17 -0
  121. data/vendor/prelude-ls/src/List.ls +299 -0
  122. data/vendor/prelude-ls/src/Num.ls +83 -0
  123. data/vendor/prelude-ls/src/Obj.ls +61 -0
  124. data/vendor/prelude-ls/src/Str.ls +32 -0
  125. data/vendor/prelude-ls/src/index.ls +56 -0
  126. data/vendor/prelude-ls/test/Func.ls +36 -0
  127. data/vendor/prelude-ls/test/List.ls +751 -0
  128. data/vendor/prelude-ls/test/Num.ls +258 -0
  129. data/vendor/prelude-ls/test/Obj.ls +145 -0
  130. data/vendor/prelude-ls/test/Prelude.ls +49 -0
  131. data/vendor/prelude-ls/test/Str.ls +208 -0
  132. data/vendor/prelude-ls/test/browser.html +5 -0
  133. metadata +369 -0
@@ -0,0 +1,16 @@
1
+ (function(conjur) {
2
+ 'use strict';
3
+
4
+ conjur.models.VariableList = function() {
5
+ var options = {
6
+ filter: function(member) {
7
+ var idTokens = member.id.split(':');
8
+ var id = idTokens[idTokens.length-1];
9
+ return id.split('/').length > 1;
10
+ }
11
+ };
12
+
13
+ return conjur.models.ResourceList('variable', options);
14
+ };
15
+
16
+ })(conjur);
@@ -0,0 +1,73 @@
1
+ (function(conjur, $, async, errback) {
2
+ 'use strict';
3
+
4
+ var Generic = this.Generic;
5
+
6
+ var Variable = this.Variable = function(args) {
7
+ if (!(this instanceof Variable)) {
8
+ return new Variable(args);
9
+ }
10
+
11
+ var superArguments = Array.prototype.slice.call(arguments);
12
+ superArguments.unshift('variable');
13
+ Generic.apply(this, superArguments);
14
+
15
+ return undefined;
16
+ };
17
+
18
+ Variable.prototype = Object.create(Generic.prototype);
19
+ Variable.prototype.constructor = Variable;
20
+
21
+ Variable.prototype.fetch = function(callback, custom_errback) {
22
+ var self = this,
23
+ id = this.id;
24
+
25
+ if (typeof(custom_errback) === 'undefined') {
26
+ custom_errback = errback; // reset to default
27
+ }
28
+
29
+ function members(privilege) {
30
+ return function(cb) {
31
+ $.ajax({
32
+ url: '/api/authz/'
33
+ + conjur.app.configuration.account
34
+ + '/roles/allowed_to/'
35
+ + privilege
36
+ + '/variable/'
37
+ + window.encodeURIComponent(id),
38
+ success: function(result) {
39
+ cb(null, result);
40
+ },
41
+ error: cb
42
+ });
43
+ };
44
+ }
45
+
46
+ async.parallel([
47
+ this.attributes.bind(this),
48
+ members('execute'),
49
+ members('update'),
50
+ this.resource.bind(this)
51
+ ], function(err, results) {
52
+ if (err) {
53
+ return custom_errback(err.status);
54
+ }
55
+
56
+ callback({
57
+ variable: results[0],
58
+ fetchers: results[1],
59
+ updaters: results[2],
60
+ annotations: results[3].annotations
61
+ });
62
+
63
+ return undefined;
64
+ });
65
+ };
66
+
67
+ }).bind(conjur.models.Record)
68
+ (
69
+ conjur,
70
+ jQuery,
71
+ async,
72
+ conjur.utils.errback
73
+ );
@@ -0,0 +1,205 @@
1
+ /** @jsx React.DOM */
2
+
3
+ (function(conjur, $, _, Backbone, React, SearchResults) {
4
+ 'use strict';
5
+
6
+ var GroupBox = conjur.views.GroupBox,
7
+ LayerBox = conjur.views.LayerBox,
8
+ PolicyBox = conjur.views.PolicyBox,
9
+ VariableBox = conjur.views.VariableBox,
10
+ HostBox = conjur.views.HostBox,
11
+ UserBox = conjur.views.UserBox;
12
+
13
+ conjur.Workspace = Backbone.Router.extend({
14
+ routes: {
15
+ '': 'dashboard',
16
+ 'ui': 'dashboard',
17
+ 'ui/users': 'users',
18
+ 'ui/users/:user': 'user',
19
+ 'ui/groups': 'groups',
20
+ 'ui/groups/:group': 'group',
21
+ 'ui/hosts': 'hosts',
22
+ 'ui/hosts/:host': 'host',
23
+ 'ui/layers': 'layers',
24
+ 'ui/layers/:layer': 'layer',
25
+ 'ui/variables': 'variables',
26
+ 'ui/variables/:variable': 'variable',
27
+ 'ui/policies': 'policies',
28
+ 'ui/policies/:policy': 'policy',
29
+ 'ui/audit': 'audit',
30
+ 'ui/search/:search': 'search'
31
+ },
32
+
33
+ activateList: function(componentFunction) {
34
+ /* console.log('List', kind); */
35
+ this.setActiveNav(conjur.app.kind);
36
+ conjur.app.namespace.currentNamespace = '';
37
+
38
+ conjur.app.lists[conjur.app.kind].fetch(function(list) {
39
+ var component = componentFunction(list);
40
+ // doesn't make much sense due to http://stackoverflow.com/questions/24889934/componentinstance-setstate-undefined-in-0-11-0
41
+ //components[kind] = component;
42
+
43
+ React.renderComponent(
44
+ component,
45
+ document.getElementById('content')
46
+ );
47
+
48
+ // state reset won't work anymore in react v11, plus I am not sure how it is supposed to work, if namespace was just reset to zero
49
+ // component.setState({currentNamespace: namespace.currentNamespace, members: list.members(namespace.currentNamespace)});
50
+ });
51
+ },
52
+
53
+ activateRecord: function(k, id, componentFunction) {
54
+ /* console.log('Record', k, ' :', id); */
55
+
56
+ $('#inlineSearchContainer').show();
57
+ conjur.app.kind = conjur.utils.pluralize(k);
58
+ this.setActiveNav(conjur.app.kind);
59
+
60
+ var model;
61
+ var Record = conjur.models.Record;
62
+
63
+ if (Record[_.capitalize(k)]) {
64
+ model = new Record[_.capitalize(k)](id);
65
+ } else {
66
+ model = new Record.Generic(conjur.app.kind, id);
67
+ }
68
+
69
+ model.fetch(function(record) {
70
+ var component = componentFunction(record);
71
+
72
+ React.renderComponent(
73
+ component,
74
+ document.getElementById('content')
75
+ );
76
+ }, function(status, text, xhr) {
77
+ if (status == 403) {
78
+ conjur.app.flash = 'You are not authorized to view ' + conjur.app.kind + ':' + id + '.';
79
+ window.history.back();
80
+ } else {
81
+ console.error('HTTP error: ', status, text);
82
+ }
83
+ });
84
+ },
85
+
86
+ setActiveNav: function(name) {
87
+ $('.nav-item').removeClass('active');
88
+ $('#nav-' + name).addClass('active');
89
+ },
90
+
91
+ dashboard: function() {
92
+ $('#inlineSearchContainer').hide();
93
+ React.renderComponent(
94
+ <Dashboard />,
95
+ document.getElementById('content')
96
+ );
97
+ },
98
+
99
+ user: function(user) {
100
+ this.activateRecord('user', user, function(record) {
101
+ return <User data={record}/>;
102
+ });
103
+ },
104
+
105
+ users: function() {
106
+ $('#inlineSearchContainer').show();
107
+ conjur.app.kind = 'users';
108
+
109
+ this.activateList(function(list) {
110
+ return <UserBox data={{namespaces: list.namespaces, members: list.members('')}} />;
111
+ });
112
+ },
113
+
114
+ group: function(group) {
115
+ this.activateRecord('group', group, function(record) {
116
+ return <Group data={record} />;
117
+ });
118
+ },
119
+
120
+ groups: function() {
121
+ $('#inlineSearchContainer').show();
122
+ conjur.app.kind = 'groups';
123
+
124
+ this.activateList(function(list) {
125
+ return <GroupBox data={{namespaces: list.namespaces, members: list.members('')}} />;
126
+ });
127
+ },
128
+
129
+ host: function(host){
130
+ this.activateRecord('host', host, function(record) {
131
+ return <Host data={record}/>;
132
+ });
133
+ },
134
+
135
+ hosts: function() {
136
+ $('#inlineSearchContainer').show();
137
+ conjur.app.kind = 'hosts';
138
+ var HostBox = conjur.views.HostBox;
139
+
140
+ this.activateList(function(list) {
141
+ return <HostBox data={{namespaces: list.namespaces, members: list.members('')}} />;
142
+ });
143
+ },
144
+
145
+ layer: function(layer) {
146
+ this.activateRecord('layer', layer, function(record) {
147
+ return <Layer data={record} />;
148
+ });
149
+ },
150
+
151
+ layers: function() {
152
+ $('#inlineSearchContainer').show();
153
+ conjur.app.kind = 'layers';
154
+
155
+ this.activateList(function(list) {
156
+ return <LayerBox data={{namespaces: list.namespaces, members: list.members('')}} />;
157
+ });
158
+ },
159
+
160
+ variable: function(variable) {
161
+ this.activateRecord('variable', variable, function(record) {
162
+ return <Variable data={record} />;
163
+ });
164
+ },
165
+
166
+ variables: function() {
167
+ $('#inlineSearchContainer').show();
168
+ conjur.app.kind = 'variables';
169
+
170
+ this.activateList(function(list) {
171
+ return <VariableBox data={{namespaces: list.namespaces, members: list.members('')}} />;
172
+ });
173
+ },
174
+
175
+ policies: function() {
176
+ conjur.app.kind = 'policies';
177
+
178
+ this.activateList(function(list) {
179
+ return <PolicyBox data={{members: list.members('')}} />;
180
+ });
181
+ },
182
+
183
+ policy: function(policy) {
184
+ this.activateRecord('policy', policy, function(record) {
185
+ return <Policy data={record} />;
186
+ });
187
+ },
188
+
189
+ audit: function(){
190
+ $('#inlineSearchContainer').show();
191
+ this.setActiveNav('audit');
192
+
193
+ React.renderComponent(
194
+ <GlobalAudit/>,
195
+ document.getElementById('content')
196
+ );
197
+ },
198
+
199
+ search: function(search){
200
+ $('#inlineSearchContainer').show();
201
+ SearchResults.search(search);
202
+ }
203
+ });
204
+
205
+ })(conjur, jQuery, _, Backbone, React, SearchResults);
@@ -0,0 +1,36 @@
1
+ /** @jsx React.DOM */
2
+
3
+ var AnnotationsBox = React.createClass({
4
+ render: function() {
5
+
6
+ if (!this.props.annotations || !this.props.annotations.length>0 ) {
7
+ return <div>
8
+ <span>None</span>
9
+ </div>;
10
+ }
11
+
12
+ // TODO: sort by date (optionally)
13
+ // TODO: table view
14
+ var annotations_list = [];
15
+ this.props.annotations.sort(function(a,b) {
16
+ return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
17
+ }).forEach(function(item){
18
+ var itemname = item.name;
19
+ var itemvalue = item.value;
20
+
21
+ var dt_key = "annotation_"+itemname+"_key";
22
+ var dd_key = "annotation_"+itemname+"_value";
23
+
24
+ annotations_list.push(<dt key={dt_key}>{itemname}</dt>);
25
+ annotations_list.push(<dd key={dd_key}>{itemvalue}</dd>);
26
+ });
27
+
28
+
29
+ return <div>
30
+ <dl className="annotations dl-horizontal">
31
+ {annotations_list}
32
+ </dl>
33
+ </div>;
34
+ }
35
+ }
36
+ );
@@ -0,0 +1,363 @@
1
+ /**@jsx React.DOM*/
2
+
3
+ // Generated by LiveScript 1.2.0
4
+ (function(){
5
+ var ref$, em, strong, table, div, th, tr, td, thead, tbody, section, h3, time, map, each, unique, isType, join, compact_fields, extended_fields, FieldsMixin, AuditTableHeader, Timestamp, wrapArray, AuditEntry, newEventSet, AuditTable, GlobalAudit, urlOfRole, urlOfResource, AuditBox, out$ = typeof exports != 'undefined' && exports || this, slice$ = [].slice;
6
+ ref$ = React.DOM, em = ref$.em, strong = ref$.strong, table = ref$.table, div = ref$.div, th = ref$.th, tr = ref$.tr, td = ref$.td, thead = ref$.thead, tbody = ref$.tbody, section = ref$.section, h3 = ref$.h3, time = ref$.time;
7
+ ref$ = require('prelude-ls'), map = ref$.map, each = ref$.each, unique = ref$.unique, isType = ref$.isType, join = ref$.join;
8
+ compact_fields = ['auditview_user', 'auditview_action'];
9
+ //extended_fields = ['timestamp', 'user', 'acting_as', 'action', 'entities', 'privilege','human'];
10
+ extended_fields = ['timestamp','auditview_user','auditview_action'];
11
+ known_rolsource_types = [ 'user','group','host','layer','policy']; // what if somebody explicitly will create the role of such type?
12
+ FieldsMixin = {
13
+ fields: function(){
14
+ if (this.props.compact) {
15
+ return compact_fields;
16
+ } else {
17
+ return extended_fields;
18
+ }
19
+ }
20
+ };
21
+ AuditTableHeader = React.createClass({
22
+ mixins: [FieldsMixin],
23
+ displayName: 'AuditTableHeader',
24
+ render: function(){
25
+ return thead({}, tr({}, map(function(it){
26
+ return th({
27
+ key: it
28
+ }, it.replace('auditview_','').replace('_', ' '));
29
+ })(
30
+ this.fields())));
31
+ }
32
+ });
33
+ Timestamp = React.createClass({
34
+ displayName: 'Timestamp',
35
+ render: function(){
36
+ var ts;
37
+ ts = moment(this.props.time); /*.format('YYYY-MM-DD hh:mm:ss');
38
+ return <div className="timestamp">{ts}</div>;
39
+ */
40
+ return time({
41
+ className: "timestamp",
42
+ dateTime: ts.format(),
43
+ title: ts.calendar()
44
+ }, [ts.fromNow()]);
45
+ }
46
+ });
47
+ wrapArray = function(it){
48
+ if (isType('Array', it)) {
49
+ return it;
50
+ } else {
51
+ return [it];
52
+ }
53
+ };
54
+ out$.AuditEntry = AuditEntry = React.createClass({
55
+ mixins: [FieldsMixin],
56
+ displayName: 'AuditEntry',
57
+ // TODO: make message a separate React Class
58
+ humanizeEvent: function(e) {
59
+ // copy of SHORT_FORMATS logic from cli-ruby:lib/conjur/command/audit.rb
60
+ var msg="";
61
+
62
+ if ((e.kind=='resource') && (e.action=='check')) {
63
+ msg = [ ]
64
+ if ( e.allowed ) {
65
+ msg.push("performed ");
66
+ msg.push(em({}, e.privilege));
67
+ msg.push(" on ");
68
+ msg.push(ResourceLink({id: e.resource, noIcon: true}));
69
+ }
70
+ else {
71
+ msg.push("was ");
72
+ msg.push(strong({}, "denied permission"));
73
+ msg.push(" to ");
74
+ msg.push(em({}, e.privilege));
75
+ msg.push(" ");
76
+ msg.push(ResourceLink({id: e.resource, noIcon: true}));
77
+ }
78
+ } else if ((e.kind=="resource") && (e.action=="create")) {
79
+ msg = [ " created ", ResourceLink({id: e.resource, noIcon: true}), " owned by ", RoleLink({id: e.owner, noIcon: true}) ];
80
+ } else if ((e.kind=="resource") && (e.action=="update")) { // this is suspicious, but CLI audit does this
81
+ msg = [ " gave ", ResourceLink({id: e.resource, noIcon: true}), " to ", RoleLink({id: e.owner, noIcon: true}) ];
82
+ } else if ((e.kind=="resource") && (e.action=="destroy")) {
83
+ msg = [ " deleted ", ResourceLink({id: e.resource, noIcon: true}) ];
84
+ } else if ((e.kind=="resource") && (e.action=="permit")) {
85
+ msg = [ " permitted ", RoleLink({id: e.grantee, noIcon: true}), " to ", em({}, e.privilege), " ", ResourceLink({id: e.resource, noIcon: true}) ]
86
+ if ( e.grant_option )
87
+ msg.push(" with grant option");
88
+ } else if ((e.kind=="resource") && (e.action=="deny")) {
89
+ msg = [ " denied ", em({}, e.privilege), " from ", RoleLink({id: e.grantee, noIcon: true}), " on ", ResourceLink({id: e.resource, noIcon: true}) ];
90
+ } else if ((e.kind=="resource") && (e.action=="permitted_roles")) {
91
+ msg = [ " listed roles permitted to ", em({}, e.privilege), " on ", ResourceLink({id: e.resource, noIcon: true}) ];
92
+ } else if ((e.kind=="role") && (e.action=="check")) {
93
+ msg = [ ]
94
+ if ( e.allowed ) {
95
+ msg.push(RoleLink({id: e.role, noIcon: true}))
96
+ msg.push(" performed ");
97
+ msg.push(em({}, e.privilege));
98
+ msg.push(" on ");
99
+ msg.push(ResourceLink({id: e.resource, noIcon: true}));
100
+ }
101
+ else {
102
+ msg.push(RoleLink({id: e.role, noIcon: true}))
103
+ msg.push(" was ");
104
+ msg.push(strong({}, "denied permission"));
105
+ msg.push(" to ");
106
+ msg.push(em({}, e.privilege));
107
+ msg.push(" on ");
108
+ msg.push(ResourceLink({id: e.resource, noIcon: true}));
109
+ }
110
+ } else if ((e.kind=="role") && (e.action=="grant")) {
111
+ /* what was the point of commenting this out? */
112
+ msg = [ " granted role ", RoleLink({id: e.role, noIcon: true}), " to ", RoleLink({id: e.member, noIcon: true}) ];
113
+ if (e.admin_option) {
114
+ msg.push(" with admin permission");
115
+ } else {
116
+ msg.push(" without admin permission");
117
+ }
118
+ } else if ((e.kind=="role") && (e.action=="revoke")) {
119
+ msg = [ " revoked role ", RoleLink({id: e.role, noIcon: true}), " from ", RoleLink({id: e.member, noIcon: true}) ];
120
+ } else if ((e.kind=="role") && (e.action=="create")) {
121
+ msg = [ " created role ", RoleLink({id: e.role, noIcon: true}) ];
122
+ } else if ((e.kind=="annotation") && (e.action=="update")) {
123
+ msg = [ " updated annotation on ", ResourceLink({id: e.resource, noIcon: true}) ];
124
+ } else if (e.kind=="audit") {
125
+ var action_part = _.compact([e.facility, e.action]).join(":");
126
+ var parts = [action_part];
127
+ if (e.role!=null) {
128
+ parts.push(" by ");
129
+ parts.push(RoleLink({id: e.role, noIcon: true}));
130
+ }
131
+ if (e.resource_id!=null) {
132
+ parts.push(" on");
133
+ parts.push(ResourceLink({id: e.resource_id, noIcon: true}));
134
+ }
135
+ if (e.allowed!=null) {
136
+ parts.push(" (allowed: "+e.allowed+")");
137
+ }
138
+ var statement = parts.join(" ");
139
+ msg = [" reported ", parts ];
140
+ if (e.audit_message!=null) {
141
+ msg.push("; message: ");
142
+ msg.push(e.audit_message);
143
+ }
144
+ } else {
145
+ msg+=" unknown event: "+e.kind+":"+e.action+"!";
146
+ }
147
+
148
+ if (e.error!=null) {
149
+ msg+=" (failed with "+e.error+")";
150
+ }
151
+
152
+ return msg;
153
+ },
154
+ transformField: function(key, value){
155
+ var that;
156
+ switch (key) {
157
+ case 'entities':
158
+ return [
159
+ (that = this.props.resource) != null ? ResourceLink({
160
+ data: that
161
+ }) : void 8, (that = this.props.role) != null ? RoleLink({
162
+ id: that
163
+ }) : void 8
164
+ ];
165
+ case 'user':
166
+ if (value != null) {
167
+ return RoleLink({
168
+ id: value
169
+ });
170
+ }
171
+ break;
172
+ case 'acting_as':
173
+ that = this.props.user;
174
+ if ((value != null) && ( value != that )) {
175
+ return RoleLink({
176
+ id: value
177
+ });
178
+ }
179
+ break;
180
+ case 'auditview_user': //virtual field
181
+ var acting_user =this.props.user;
182
+ var acting_role = this.props.acting_as;
183
+ msg = [ RoleLink({id: acting_user}) ];
184
+ if ((acting_role!=null) && (acting_role != acting_user)) {
185
+ msg.push([" as ", RoleLink({id: acting_role})]);
186
+ }
187
+ return msg;
188
+ case 'timestamp':
189
+ if (value != null) {
190
+ return Timestamp({
191
+ time: value
192
+ });
193
+ }
194
+ break;
195
+ case 'auditview_action':
196
+ return this.humanizeEvent(this.props);
197
+ default:
198
+ return value;
199
+ }
200
+ },
201
+ render: function(){
202
+ var this$ = this;
203
+ return tr({
204
+ className: this.props.action
205
+ }, map(function(it){
206
+ return td.apply(null, [{
207
+ key: it
208
+ }].concat(slice$.call(wrapArray(this$.transformField(it, this$.props[it])))));
209
+ })(
210
+ this.fields()));
211
+ }
212
+ });
213
+ newEventSet = function(){
214
+ var evts;
215
+ evts = new SortedSet({
216
+ comparator: function(a, b){
217
+ return a && b && b.id - a.id;
218
+ }
219
+ });
220
+ evts.containsLike = function(item){
221
+ var existing;
222
+ existing = this.findIterator(item).value();
223
+ if (existing != null) {
224
+ return this.priv.comparator(existing, item) === 0;
225
+ }
226
+ };
227
+ return evts;
228
+ };
229
+ out$.AuditTable = AuditTable = React.createClass({
230
+ displayName: 'AuditTable',
231
+ getInitialState: function(){
232
+ return {
233
+ events: newEventSet()
234
+ };
235
+ },
236
+ knownRolsourceTypes: function() {
237
+ return ;
238
+ },
239
+ render: function(){
240
+ var compact;
241
+ compact = this.props.compact;
242
+ return section({
243
+ className: 'audit'
244
+ }, [
245
+ h3({}, this.props.caption), table({
246
+ className: 'audit-table'
247
+ }, [
248
+ AuditTableHeader({
249
+ key: 'thead',
250
+ compact: compact
251
+ }), tbody({
252
+ key: 'tbody'
253
+ }, this.state.events.filter(function(ev){
254
+ // remove internal resources creation
255
+ if ((ev.role!=null) && (ev.role.split(':')[1] == '@')) {
256
+ return false;
257
+ }
258
+ if ((ev.resource!=null) && (ev.resource.split(':')[1] == '@')) {
259
+ return false;
260
+ }
261
+ if ((ev.resource!=null) && (ev.resource.split(':')[1] == 'secret')) {
262
+ return false;
263
+ }
264
+ if ((ev.grantee!=null) && (ev.grantee.split(':')[1] == '@')) {
265
+ return false;
266
+ }
267
+
268
+ // hide automated creation of roles corresponding to resources of known type
269
+ if ((ev.kind=="role") && (ev.action=="create")) {
270
+ var rolekind = ev.role.split(':')[1];
271
+ if (_.contains(known_rolsource_types, rolekind)) {
272
+ return false;
273
+ }
274
+ }
275
+ return true;
276
+ }).map(function(it){
277
+ // new way to clone objects, custom clone$ does not work no more as expected
278
+ var ref$ = React.addons.update(it, {$merge: {key: it.id, compact: compact} });
279
+ return new AuditEntry(ref$);
280
+ }))
281
+ ])
282
+ ]);
283
+ },
284
+ componentDidMount: function(){
285
+ return each(this.addSource)(
286
+ wrapArray(
287
+ this.props.src));
288
+ },
289
+ componentWillUnmount: function(){
290
+ return each(function(it){
291
+ console.log("closing event source ", it);
292
+ return it.close();
293
+ })(
294
+ this.sources);
295
+ },
296
+ addEvent: function(arg$){
297
+ var data, event;
298
+ data = arg$.data;
299
+ event = JSON.parse(data);
300
+ if (event.action === "check" && event.privilege === "read" && event.allowed) {
301
+ return true;
302
+ } else {
303
+ if (!this.state.events.containsLike(event)) {
304
+ this.state.events.insert(event);
305
+ return this.forceUpdate();
306
+ }
307
+ }
308
+ },
309
+ addSource: function(url){
310
+ var evtSrc;
311
+ console.log("opening eventsource to " + url);
312
+ evtSrc = new EventSource(url);
313
+ console.log(evtSrc);
314
+ evtSrc.onmessage = this.addEvent;
315
+ evtSrc.onerror = function(a, b, c, d){
316
+ return console.log(a, b, c, d);
317
+ };
318
+ return (this.sources || (this.sources = [])).push(evtSrc);
319
+ }
320
+ });
321
+ out$.GlobalAudit = GlobalAudit = React.createClass({
322
+ displayName: 'GlobalAudit',
323
+ render: function(){
324
+ return AuditTable({
325
+ src: '/api/audit/all',
326
+ caption: 'All recent audit events'
327
+ });
328
+ }
329
+ });
330
+ urlOfRole = function(role){
331
+ return "/api/audit/roles/" + encodeURIComponent(role);
332
+ };
333
+ urlOfResource = function(resource){
334
+ return "/api/audit/resources/" + encodeURIComponent(resource);
335
+ };
336
+ out$.AuditBox = AuditBox = React.createClass({
337
+ displayName: 'AuditBox',
338
+ render: function(){
339
+ var roles, resources, roleSrcs, resSrcs, things;
340
+ roles = this.props.roles || [];
341
+ resources = this.props.resources || [];
342
+ roleSrcs = map(urlOfRole)(
343
+ roles);
344
+ resSrcs = map(urlOfResource)(
345
+ resources);
346
+ things = join(', ')(
347
+ unique(
348
+ roles.concat(resources)));
349
+
350
+ var options= { src: roleSrcs.concat(resSrcs) };
351
+ if (this.props.tabview==null) {
352
+ options=_.extend(options, {caption: "Recent Activity"});
353
+ }
354
+ return AuditTable(options);
355
+ }
356
+ });
357
+ /* it does not work as expected with new react any more (prototype fields are squashed within react)
358
+ function clone$(it){
359
+ function fun(){} fun.prototype = it;
360
+ return new fun;
361
+ }
362
+ */
363
+ }).call(this);