conjur-asset-ui-api 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d4e58d15d8bff87b2a55387b4ceedf751fa4196f
4
- data.tar.gz: 72c9f5cc63f114979e19b0b6a4d3034b71999450
3
+ metadata.gz: 7411cf0ff97005386a475d49c0fc2dfc015504c0
4
+ data.tar.gz: f0f45c605c547afa2d6216472d0c04967b3318c0
5
5
  SHA512:
6
- metadata.gz: d361ca37db90dda03a4a74c55447f4e41778d305466a4d28022de0c1aa546b4a87066cec7f460761a81acb88bae70401a14dbd4d7c72ad665154fe9bc6536012
7
- data.tar.gz: 0c8c2dc7a6fcdb2a59a9b8189ae4421c6e2af6ed51440a3d92e0a042efa4a9c8c54e8adb84afe84cdd6c952e4ac87a0a6c3269536a6efebd86f993d8bcbef499
6
+ metadata.gz: 56229687c796bffce448229fd4711c99bb78193b1cf2751c99d50d43a98e0bb0a4fa1fe0c5518d0709ce2e77ebfddf7d1e7368fbc5531da5ac3126c64cc0ce9e
7
+ data.tar.gz: 397fb524b5499af16448d2f3496a469054aa18ca77d64b1bfb1562329bbf44960a410f6968d893e1438f8977c4c2bd9977c09b3bdd843217af60a2939ede437a
data/Rakefile CHANGED
@@ -1 +1,3 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'jasmine'
3
+ load 'jasmine/tasks/jasmine.rake'
data/compile_ls CHANGED
@@ -1,2 +1,6 @@
1
1
  #!/bin/bash
2
- lsc -w -c -o public/js livescript
2
+ lsc -w -c -o public/js livescript &
3
+ lsc -w -c -o spec spec &
4
+ while sleep 42; do true; done
5
+ kill `jobs -p`
6
+
@@ -33,4 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "simplecov"
34
34
  spec.add_development_dependency "spork"
35
35
  spec.add_development_dependency "ci_reporter"
36
+ spec.add_development_dependency "jasmine"
36
37
  end
@@ -1,7 +1,7 @@
1
1
  module Conjur
2
2
  module Asset
3
3
  module UI
4
- VERSION="1.1.1"
4
+ VERSION="1.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -2,35 +2,41 @@ require 'time'
2
2
  require 'rack/utils'
3
3
  require 'rack/mime'
4
4
 
5
+ require 'conjur/webserver/renderer'
6
+
5
7
  module Conjur
6
8
  module WebServer
7
9
  class Home
8
- F = ::File
9
-
10
10
  def initialize(root)
11
11
  @root = root
12
12
  end
13
-
13
+
14
14
  # From Rack::File
15
15
  def call(env)
16
- path = File.expand_path("index.html", @root)
16
+ path = File.expand_path(INDEX, @root)
17
+ renderer = Renderer.new @root
18
+
19
+ page = renderer.render File.read(path)
20
+ files = renderer.files + [path]
21
+
22
+ last_modified = files.map(&File.method(:mtime)).max.httpdate
17
23
 
18
- if env["REQUEST_METHOD"] == "OPTIONS"
19
- return [200, {'Allow' => ALLOW_HEADER, 'Content-Length' => '0'}, []]
20
- end
21
- last_modified = F.mtime(path).httpdate
22
24
  return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified
23
25
 
24
- size = F.size?(path) || Rack::Utils.bytesize(F.read(path))
25
-
26
- headers = {
26
+ size = Rack::Utils.bytesize(page)
27
+
28
+ headers = {
27
29
  "Last-Modified" => last_modified,
28
30
  "Content-Type" => "text/html",
29
31
  "Content-Length" => size.to_s
30
32
  }
31
-
32
- [ 200, headers, env["REQUEST_METHOD"] == "HEAD" ? [] : [ F.read(path) ] ]
33
+
34
+ [200, headers, env["REQUEST_METHOD"] == "HEAD" ? [] : [page]]
33
35
  end
36
+
37
+ private
38
+
39
+ INDEX = 'index.html.erb'.freeze
34
40
  end
35
41
  end
36
42
  end
@@ -10,6 +10,12 @@ module Conjur
10
10
 
11
11
  def call(env)
12
12
  if sessionid = token_valid?(env)
13
+ require 'conjur/authn'
14
+ require 'base64'
15
+ token = Conjur::Authn.authenticate
16
+ api = Conjur::API.new_from_token token
17
+ userid = [ Conjur.configuration.account, "user", api.username ].join(':')
18
+
13
19
  env["rack.session"][:sessionid] = sessionid
14
20
  response = Rack::Response.new(env)
15
21
  configuration = {
@@ -20,6 +26,7 @@ module Conjur
20
26
  }
21
27
  response.status = 302
22
28
  response.set_cookie('conjur_configuration', value: JSON.pretty_generate(configuration), path: '/')
29
+ response.set_cookie('conjur_userid', value: userid, path: '/')
23
30
  response['Location'] = "/ui"
24
31
  response.finish
25
32
  else
@@ -0,0 +1,34 @@
1
+ module Conjur
2
+ module WebServer
3
+ # a helper class to render HTML partials
4
+ class Renderer
5
+ def initialize root
6
+ @root = root
7
+ @files = []
8
+ end
9
+
10
+ attr_reader :files
11
+
12
+ def render template
13
+ ERB.new(template).result binding
14
+ end
15
+
16
+ private
17
+
18
+ def method_missing name, *a, &b
19
+ super if !a.empty? || block_given?
20
+
21
+ # try to load fragments
22
+ path = expand_path "_#{name}.html"
23
+ super unless File.exists? path
24
+
25
+ @files << path
26
+ File.read path
27
+ end
28
+
29
+ def expand_path filename
30
+ File.expand_path(filename, @root)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,20 +1,31 @@
1
1
  {table, div, th, tr, td, thead, tbody, section, h3, time} = React.DOM
2
2
  {map, each, unique, is-type, join} = require 'prelude-ls'
3
3
 
4
- fields = <[ timestamp user acting_as action kind entity privilege ]>
4
+ compact_fields = <[ user action entities ]>
5
+ extended_fields = <[ timestamp user acting_as action entities privilege ]>
5
6
 
7
+ FieldsMixin = {
8
+ fields: ->
9
+ if @props.compact
10
+ compact_fields
11
+ else
12
+ extended_fields
13
+ }
6
14
 
7
15
  AuditTableHeader = React.createClass {
16
+ mixins: [ FieldsMixin ]
17
+
8
18
  display-name: \AuditTableHeader
19
+
9
20
  render: ->
10
- thead {}, (tr {}, (fields |> map -> th key: it, it.replace \_, ' '))
21
+ thead {}, (tr {}, (@fields() |> map -> th key: it, it.replace \_, ' '))
11
22
  }
12
23
 
13
24
  Timestamp = React.createClass {
14
25
  display-name: \Timestamp
15
26
  render: ->
16
27
  ts = moment(@props.time)
17
- time datetime: ts.format!, title: ts.calendar!, [ ts.from-now! ]
28
+ time date-time: ts.format!, title: ts.calendar!, [ ts.from-now! ]
18
29
  }
19
30
 
20
31
  wrap-array = ->
@@ -23,24 +34,24 @@ wrap-array = ->
23
34
  else
24
35
  [it]
25
36
 
26
- AuditEntry = React.createClass {
27
- display-name: \AuditEntry
37
+ export AuditEntry = React.createClass {
38
+ mixins: [ FieldsMixin ]
28
39
 
29
- transformed-props: ->
30
- @props with
31
- entity: @props.resource || @props.role
40
+ display-name: \AuditEntry
32
41
 
33
42
  transform-field: (key, value) ->
34
- | not value => value # need this case to handle blank values that turn up sometimes
35
- | key in <[ user acting_as ]> => RoleLink {id: value}
36
- | key == 'entity' => ResourceLink {data: value}
37
- | key == 'timestamp' => Timestamp {time: value}
38
- | otherwise => value
43
+ switch key
44
+ | \entities => [
45
+ if @props.resource? then ResourceLink data: that
46
+ if @props.role? then RoleLink id: that
47
+ ]
48
+ | <[ user acting_as ]> => RoleLink {id: value} if value?
49
+ | \timestamp => Timestamp {time: value} if value?
50
+ | _ => value
39
51
 
40
52
  render: ->
41
- props = @transformed-props!
42
53
  tr class-name: @props.action,
43
- fields |> map ~> td key: it, [ @transform-field(it, props[it]) ]
54
+ @fields() |> map ~> td key: it, ...wrap-array(@transform-field(it, @props[it]))
44
55
  }
45
56
 
46
57
  # compare events by id to prevent duplicates
@@ -52,19 +63,20 @@ new-event-set = ->
52
63
  @priv.comparator(existing, item) == 0 if existing?
53
64
  evts
54
65
 
55
- AuditTable = React.createClass {
66
+ export AuditTable = React.createClass {
56
67
  display-name: \AuditTable
57
68
 
58
69
  get-initial-state: ->
59
70
  events: new-event-set!
60
71
 
61
72
  render: ->
73
+ compact = @props.compact
62
74
  section class-name: \audit, [
63
75
  h3 {}, @props.caption
64
76
  table class-name: \audit-table, [
65
- AuditTableHeader(key: \thead),
77
+ AuditTableHeader(key: \thead, compact: compact),
66
78
  tbody key: \tbody,
67
- @state.events.map -> new AuditEntry it with key: it.id
79
+ @state.events.map -> new AuditEntry it with key: it.id, compact: compact
68
80
  ]
69
81
  ]
70
82
 
@@ -119,6 +131,6 @@ export AuditBox = React.createClass {
119
131
  things = (roles ++ resources) |> unique |> join ', '
120
132
  AuditTable {
121
133
  src: role-srcs ++ res-srcs
122
- caption: "Recent audit events for #things"
134
+ caption: "Recent Activity"
123
135
  }
124
136
  }
@@ -0,0 +1,37 @@
1
+ <script src="/js/models/namespace.js"></script>
2
+ <script src="/js/models/resourceList.js"></script>
3
+ <script src="/js/models/policyList.js"></script>
4
+ <script src="/js/models/userList.js"></script>
5
+ <script src="/js/models/variableList.js"></script>
6
+ <script src="/js/models/record.js"></script>
7
+ <script src="/js/models/groupRecord.js"></script>
8
+ <script src="/js/models/layerRecord.js"></script>
9
+ <script src="/js/models/variableRecord.js"></script>
10
+ <script src="/js/models/hostRecord.js"></script>
11
+ <script src="/js/models/userRecord.js"></script>
12
+ <script type="text/jsx" src="/js/views/mixins/search.js"></script>
13
+ <script type="text/jsx" src="/js/views/owned.js"></script>
14
+ <script type="text/jsx" src="/js/views/audit.js"></script>
15
+ <script type="text/jsx" src="/js/views/dashboard.js"></script>
16
+ <script type="text/jsx" src="/js/views/generic.js"></script>
17
+ <script type="text/jsx" src="/js/views/namespaces.js"></script>
18
+ <script type="text/jsx" src="/js/views/users.js"></script>
19
+ <script type="text/jsx" src="/js/views/hosts.js"></script>
20
+ <script type="text/jsx" src="/js/views/host.js"></script>
21
+ <script type="text/jsx" src="/js/views/role.js"></script>
22
+ <script type="text/jsx" src="/js/views/group.js"></script>
23
+ <script type="text/jsx" src="/js/views/groups.js"></script>
24
+ <script type="text/jsx" src="/js/views/layer.js"></script>
25
+ <script type="text/jsx" src="/js/views/layers.js"></script>
26
+ <script type="text/jsx" src="/js/views/variable.js"></script>
27
+ <script type="text/jsx" src="/js/views/variables.js"></script>
28
+ <script type="text/jsx" src="/js/views/policies.js"></script>
29
+ <script type="text/jsx" src="/js/views/policy.js"></script>
30
+ <script type="text/jsx" src="/js/views/resource.js"></script>
31
+ <script type="text/jsx" src="/js/views/permissions.js"></script>
32
+ <script type="text/jsx" src="/js/views/user.js"></script>
33
+ <script type="text/jsx" src="/js/views/time.js"></script>
34
+ <script type="text/jsx" src="/js/views/navSearch.js"></script>
35
+ <script type="text/jsx" src="/js/views/searchResults.js"></script>
36
+ <script src="/js/views/audit.js"></script>
37
+ <script type="text/jsx" src="/js/main.js"></script>
@@ -0,0 +1,21 @@
1
+ <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
2
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
3
+ <!--[if lt IE 9]>
4
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
5
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
6
+ <![endif]-->
7
+
8
+ <script src="/js/lib/sorted-set.no-require.js"></script>
9
+ <script src="/js/lib/less.js"></script>
10
+ <script src="/js/lib/react-with-addons.js"></script>
11
+ <script src="/js/lib/JSXTransformer.js"></script>
12
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
13
+ <script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
14
+ <script src="/js/lib/async.js"></script>
15
+ <script src="/js/lib/underscore-min.js"></script>
16
+ <script src="/js/lib/underscore.string.min.js"></script>
17
+ <script src="/js/lib/backbone.js"></script>
18
+ <script src="/js/lib/bootstrap.js"></script>
19
+ <script src="/js/lib/date.extensions.js"></script>
20
+ <script src="/js/lib/moment.js"></script>
21
+ <script src="/js/lib/prelude-browser-min.js"></script>
@@ -154,17 +154,17 @@ dl.propertyList {
154
154
  .role-link-icon('/images/icon-environment.png', 1.1em);
155
155
  }
156
156
 
157
- .host.role-link {
157
+ .host.role-link, .host.resource-link {
158
158
  .role-link-icon('/images/icon-client-pc.svg');
159
159
  background-position-y: -0.1em;
160
160
  }
161
161
 
162
- .user.role-link {
162
+ .user.role-link, .user.resource-link {
163
163
  .role-link-icon('/images/icon-person.svg');
164
164
  background-position-y: -0.2em;
165
165
  }
166
166
 
167
- .group.role-link {
167
+ .group.role-link, .group.resource-link {
168
168
  .role-link-padding;
169
169
  .group-icon(1.2em);
170
170
  }
@@ -179,6 +179,25 @@ dl.propertyList {
179
179
  margin-left: 0.5em;
180
180
  }
181
181
 
182
+
183
+ .dashboard {
184
+ #dashboard-search {
185
+ margin: 4em auto;
186
+ }
187
+
188
+ .owned ul {
189
+ margin: 0;
190
+ padding: 0;
191
+ }
192
+
193
+ .owned .hide-all { display: none; }
194
+
195
+ .owned li {
196
+ list-style-type: none;
197
+ padding: 3pt 8pt;
198
+ }
199
+ }
200
+
182
201
  .dashboard form.search, #searchResults form.search {
183
202
  margin: 0px auto;
184
203
  width: 300px;
@@ -270,7 +289,7 @@ body {
270
289
  }
271
290
 
272
291
  h3 {
273
- margin: 2em 0 1em;
292
+ margin: 1em 0 1em;
274
293
  letter-spacing: 0.01em;
275
294
  font-weight: 300;
276
295
  }
@@ -296,12 +315,6 @@ body {
296
315
  //
297
316
  // Styleguide 1.1.
298
317
  section.permissions {
299
- &.loading {
300
- h3:after {
301
- content: ' — loading, please wait…';
302
- font-weight: 300;
303
- }
304
- }
305
318
  }
306
319
 
307
320
  // The topmost content container.
@@ -0,0 +1,71 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Conjur UI</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <link href='http://fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic' rel='stylesheet' type='text/css'>
7
+
8
+ <script src="/js/lib/pace.js"></script>
9
+ <!-- Bootstrap -->
10
+ <link href="/css/bootstrap.css" rel="stylesheet">
11
+
12
+ <!-- Some styles of our own -->
13
+ <link href="/css/styles.less" rel="stylesheet/less">
14
+
15
+ <%= client_libs %>
16
+ </head>
17
+ <body>
18
+ <div class="container">
19
+ <div class="navbar navbar-default" role="navigation">
20
+ <div class="navbar-collapse collapse">
21
+ <ul class="nav navbar-nav">
22
+ <li id="nav-home" class="nav-item"><a href="/ui">Dashboard</a></li>
23
+ <li id="nav-groups" class="dropdown">
24
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
25
+ Actors <span class="caret"></span>
26
+ </a>
27
+ <ul class="dropdown-menu">
28
+ <li id="nav-users" class="nav-item"><a href="/ui/users">Users</a></li>
29
+ <li id="nav-groups" class="nav-item"><a href="/ui/groups">Groups</a></li>
30
+ <li class="divider"></li>
31
+ <li id="nav-hosts" class="nav-item"><a href="/ui/hosts">Hosts</a></li>
32
+ <li id="nav-layers" class="nav-item"><a href="/ui/layers">Layers</a></li>
33
+ </ul>
34
+ </li>
35
+ <li id="nav-assets" class="dropdown">
36
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
37
+ Assets <span class="caret"></span>
38
+ </a>
39
+ <ul class="dropdown-menu">
40
+ <li id="nav-hosts" class="nav-item"><a href="/ui/hosts">Hosts</a></li>
41
+ <li id="nav-variables" class="nav-item"><a href="/ui/variables">Variables</a></li>
42
+ <li id="nav-key-pairs" class="nav-item"><a href="/ui/key-pairs">Key Pairs</a></li>
43
+ <li id="nav-web-services" class="nav-item"><a href="/ui/webservices">Web Services</a></li>
44
+ </ul>
45
+ </li>
46
+ <li id="nav-policies" class="nav-item"><a href="/ui/policies">Policies</a></li>
47
+ <li id="nav-audit" class="nav-item"><a href="/ui/audit">Audit</a></li>
48
+ </ul>
49
+ <div class="navbar-right" id="inlineSearchContainer">
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ </div>
55
+ <div class="alert alert-danger alert-dismissable" id="flash">
56
+ <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
57
+ <span class="text"></span>
58
+ </div>
59
+ <div id="content"></div>
60
+ <div id="bottom"></div>
61
+ </div><!-- /.container -->
62
+
63
+
64
+ <div id="modal">
65
+
66
+ </div>
67
+
68
+
69
+ <%= client_code %>
70
+ </body>
71
+ </html>