cased-ruby 0.3.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +20 -15
- data/README.md +135 -54
- data/bin/cli +14 -0
- data/cased-ruby.gemspec +2 -0
- data/lib/cased.rb +1 -0
- data/lib/cased/cli.rb +13 -0
- data/lib/cased/cli/asciinema/file.rb +108 -0
- data/lib/cased/cli/asciinema/writer.rb +69 -0
- data/lib/cased/cli/authentication.rb +31 -0
- data/lib/cased/cli/identity.rb +43 -0
- data/lib/cased/cli/interactive_session.rb +121 -0
- data/lib/cased/cli/log.rb +27 -0
- data/lib/cased/cli/recorder.rb +58 -0
- data/lib/cased/cli/session.rb +292 -0
- data/lib/cased/clients.rb +7 -3
- data/lib/cased/config.rb +58 -0
- data/lib/cased/http/client.rb +13 -8
- data/lib/cased/http/error.rb +5 -2
- data/lib/cased/query.rb +6 -3
- data/lib/cased/version.rb +1 -1
- data/vendor/cache/activesupport-6.1.3.gem +0 -0
- data/vendor/cache/concurrent-ruby-1.1.8.gem +0 -0
- data/vendor/cache/faraday-1.3.0.gem +0 -0
- data/vendor/cache/faraday-net_http-1.0.1.gem +0 -0
- data/vendor/cache/i18n-1.8.9.gem +0 -0
- data/vendor/cache/json-2.5.1.gem +0 -0
- data/vendor/cache/jwt-2.2.2.gem +0 -0
- data/vendor/cache/ruby2_keywords-0.0.4.gem +0 -0
- data/vendor/cache/subprocess-1.5.4.gem +0 -0
- data/vendor/cache/tzinfo-2.0.4.gem +0 -0
- data/vendor/cache/zeitwerk-2.4.2.gem +0 -0
- metadata +51 -11
- data/vendor/cache/activesupport-6.0.3.4.gem +0 -0
- data/vendor/cache/concurrent-ruby-1.1.7.gem +0 -0
- data/vendor/cache/faraday-1.1.0.gem +0 -0
- data/vendor/cache/i18n-1.8.5.gem +0 -0
- data/vendor/cache/json-2.3.1.gem +0 -0
- data/vendor/cache/ruby2_keywords-0.0.2.gem +0 -0
- data/vendor/cache/thread_safe-0.3.6.gem +0 -0
- data/vendor/cache/tzinfo-1.2.7.gem +0 -0
- data/vendor/cache/zeitwerk-2.4.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 136251a6fad727d85e14bf64bfdb5ecf33fdba19735646c3599398c7a0e44abb
|
4
|
+
data.tar.gz: 94f191ec590bc6bd68ef98b137abbaa052c8438573bb84d9cb9b63ffec4ae8e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 613409847cfcda2948b2b3559a754ac6822fca908cec0d1a089475be19801290bf8aee866e592d00bef882b1e3b7027ead484346bd39a404c171b8205a5631fa
|
7
|
+
data.tar.gz: 3a3d8435ecce240a7cff4a83061c57412d08dd1d16e91c9995caf1f755a4706f40744e7ce11c015a4557d66ea1948b6c54caf05f893205a2f8296aedb9780e7b
|
data/Gemfile.lock
CHANGED
@@ -1,43 +1,48 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cased-ruby (0.
|
4
|
+
cased-ruby (0.4.4)
|
5
5
|
activesupport (~> 6)
|
6
6
|
dotpath (= 0.1.0)
|
7
7
|
faraday (~> 1.0)
|
8
8
|
faraday_middleware (~> 1.0)
|
9
9
|
json (~> 2)
|
10
|
+
jwt (~> 2)
|
10
11
|
net-http-persistent (~> 3.0)
|
12
|
+
subprocess (~> 1.5.0)
|
11
13
|
|
12
14
|
GEM
|
13
15
|
remote: https://rubygems.org/
|
14
16
|
specs:
|
15
|
-
activesupport (6.
|
17
|
+
activesupport (6.1.3)
|
16
18
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
-
i18n (>=
|
18
|
-
minitest (
|
19
|
-
tzinfo (~>
|
20
|
-
zeitwerk (~> 2.
|
19
|
+
i18n (>= 1.6, < 2)
|
20
|
+
minitest (>= 5.1)
|
21
|
+
tzinfo (~> 2.0)
|
22
|
+
zeitwerk (~> 2.3)
|
21
23
|
addressable (2.7.0)
|
22
24
|
public_suffix (>= 2.0.2, < 5.0)
|
23
25
|
ast (2.4.0)
|
24
26
|
byebug (11.0.1)
|
25
|
-
concurrent-ruby (1.1.
|
27
|
+
concurrent-ruby (1.1.8)
|
26
28
|
connection_pool (2.2.2)
|
27
29
|
crack (0.4.3)
|
28
30
|
safe_yaml (~> 1.0.0)
|
29
31
|
docile (1.3.2)
|
30
32
|
dotpath (0.1.0)
|
31
|
-
faraday (1.
|
33
|
+
faraday (1.3.0)
|
34
|
+
faraday-net_http (~> 1.0)
|
32
35
|
multipart-post (>= 1.2, < 3)
|
33
36
|
ruby2_keywords
|
37
|
+
faraday-net_http (1.0.1)
|
34
38
|
faraday_middleware (1.0.0)
|
35
39
|
faraday (~> 1.0)
|
36
40
|
hashdiff (1.0.1)
|
37
|
-
i18n (1.8.
|
41
|
+
i18n (1.8.9)
|
38
42
|
concurrent-ruby (~> 1.0)
|
39
43
|
jaro_winkler (1.5.4)
|
40
|
-
json (2.
|
44
|
+
json (2.5.1)
|
45
|
+
jwt (2.2.2)
|
41
46
|
minitest (5.13.0)
|
42
47
|
mocha (1.11.2)
|
43
48
|
multipart-post (2.1.1)
|
@@ -63,7 +68,7 @@ GEM
|
|
63
68
|
rubocop-performance (1.5.2)
|
64
69
|
rubocop (>= 0.71.0)
|
65
70
|
ruby-progressbar (1.10.1)
|
66
|
-
ruby2_keywords (0.0.
|
71
|
+
ruby2_keywords (0.0.4)
|
67
72
|
safe_yaml (1.0.5)
|
68
73
|
sidekiq (6.0.7)
|
69
74
|
connection_pool (>= 2.2.2)
|
@@ -74,16 +79,16 @@ GEM
|
|
74
79
|
docile (~> 1.1)
|
75
80
|
simplecov-html (~> 0.11)
|
76
81
|
simplecov-html (0.12.2)
|
77
|
-
|
78
|
-
tzinfo (
|
79
|
-
|
82
|
+
subprocess (1.5.4)
|
83
|
+
tzinfo (2.0.4)
|
84
|
+
concurrent-ruby (~> 1.0)
|
80
85
|
unicode-display_width (1.6.1)
|
81
86
|
webmock (3.8.3)
|
82
87
|
addressable (>= 2.3.6)
|
83
88
|
crack (>= 0.3.2)
|
84
89
|
hashdiff (>= 0.4.0, < 2.0.0)
|
85
90
|
yard (0.9.24)
|
86
|
-
zeitwerk (2.4.
|
91
|
+
zeitwerk (2.4.2)
|
87
92
|
|
88
93
|
PLATFORMS
|
89
94
|
ruby
|
data/README.md
CHANGED
@@ -7,16 +7,19 @@ A Cased client for Ruby applications in your organization to control and monitor
|
|
7
7
|
- [Installation](#installation)
|
8
8
|
- [Configuration](#configuration)
|
9
9
|
- [Usage](#usage)
|
10
|
-
- [
|
11
|
-
|
12
|
-
- [
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
- [Cased CLI](#cased-cli)
|
11
|
+
- [Starting an approval workflow](#starting-an-approval-workflow)
|
12
|
+
- [Audit trails](#audit-trails)
|
13
|
+
- [Publishing events to Cased](#publishing-events-to-cased)
|
14
|
+
- [Retrieving events from a Cased audit trail](#retrieving-events-from-a-cased-audit-trail)
|
15
|
+
- [Retrieving events from multiple Cased audit trails](#retrieving-events-from-multiple-cased-audit-trails)
|
16
|
+
- [Exporting events](#exporting-events)
|
17
|
+
- [Masking & filtering sensitive information](#masking--filtering-sensitive-information)
|
18
|
+
- [Disable publishing events](#disable-publishing-events)
|
19
|
+
- [Context](#context)
|
20
|
+
- [Testing](#testing)
|
19
21
|
- [Customizing cased-ruby](#customizing-cased-ruby)
|
22
|
+
- [Contributing](#contributing)
|
20
23
|
|
21
24
|
## Installation
|
22
25
|
|
@@ -56,9 +59,21 @@ Cased.configure do |config|
|
|
56
59
|
# CASED_PUBLISH_URL=https://publish.cased.com
|
57
60
|
config.publish_url = 'https://publish.cased.com'
|
58
61
|
|
62
|
+
# CASED_URL=https://app.cased.com
|
63
|
+
config.url = 'https://app.cased.com'
|
64
|
+
|
59
65
|
# CASED_API_URL=https://api.cased.com
|
60
66
|
config.api_url = 'https://api.cased.com'
|
61
67
|
|
68
|
+
# GUARD_APPLICATION_KEY=guard_application_1ntKX0P4vUbKoc0lMWGiSbrBHcH
|
69
|
+
config.guard_application_key = 'guard_application_1ntKX0P4vUbKoc0lMWGiSbrBHcH'
|
70
|
+
|
71
|
+
# GUARD_USER_TOKEN=user_1oFqlROLNRGVLOXJSsHkJiVmylr
|
72
|
+
config.guard_user_token = 'user_1oFqlROLNRGVLOXJSsHkJiVmylr'
|
73
|
+
|
74
|
+
# DENY_IF_UNREACHABLE=1
|
75
|
+
config.guard_deny_if_unreachable = true
|
76
|
+
|
62
77
|
# CASED_RAISE_ON_ERRORS=1
|
63
78
|
config.raise_on_errors = false
|
64
79
|
|
@@ -75,7 +90,100 @@ end
|
|
75
90
|
|
76
91
|
## Usage
|
77
92
|
|
78
|
-
###
|
93
|
+
### Cased CLI
|
94
|
+
|
95
|
+
Keep any command line tool available as your team grows — monitor usage, require peer approvals for sensitive operations, and receive intelligent alerts to suspicious activity.
|
96
|
+
|
97
|
+
#### Starting an approval workflow
|
98
|
+
|
99
|
+
To start an approval workflow you must first obtain your application key and the
|
100
|
+
user token for who is requesting access.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Cased.configure do |config|
|
104
|
+
config.guard_application_key = 'guard_application_1pG43HF3aRHjNTTm10zzu0tngBO'
|
105
|
+
end
|
106
|
+
|
107
|
+
authentication = Cased::CLI::Authentication.new(token: 'user_1pG43D1AzTjLR8XWJHj8B3aNZ4Y')
|
108
|
+
session = Cased::CLI::Session.new(
|
109
|
+
authentication: authentication,
|
110
|
+
reason: 'I need export our GitHub issues.',
|
111
|
+
metadata: {
|
112
|
+
organization: 'GitHub',
|
113
|
+
},
|
114
|
+
)
|
115
|
+
|
116
|
+
if session.create && session.approved?
|
117
|
+
github.issues.each do |issue|
|
118
|
+
puts issue.title
|
119
|
+
end
|
120
|
+
else
|
121
|
+
puts 'Unauthorized to export GitHub issues.'
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
If you do not have the user token you can always request it interactively.
|
126
|
+
[Cased::CLI::Identity#identify](https://github.com/cased/cased-ruby/blob/3b0c8ebd37ba7deb83236be7dba4d52c74d7e4e5/lib/cased/cli/identity.rb#L10-L21)
|
127
|
+
is a blocking operation prompting the user to visit Cased to identify
|
128
|
+
themselves, returning their user token upon identifying themselves which can be
|
129
|
+
used to start your session.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
Cased.configure do |config|
|
133
|
+
config.guard_application_key = 'guard_application_1pG43HF3aRHjNTTm10zzu0tngBO'
|
134
|
+
end
|
135
|
+
|
136
|
+
authentication = Cased::CLI::Authentication.new
|
137
|
+
identity = Cased::CLI::Identity.new
|
138
|
+
token, ip_address = identity.identify
|
139
|
+
authentication.token = token
|
140
|
+
|
141
|
+
session = Cased::CLI::Session.new(
|
142
|
+
authentication: authentication,
|
143
|
+
reason: 'I need export our GitHub issues.',
|
144
|
+
metadata: {
|
145
|
+
organization: 'GitHub',
|
146
|
+
},
|
147
|
+
)
|
148
|
+
|
149
|
+
if session.create && session.approved?
|
150
|
+
github.issues.each do |issue|
|
151
|
+
puts issue.title
|
152
|
+
end
|
153
|
+
else
|
154
|
+
puts 'Unauthorized to export GitHub issues.'
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
#### Starting an interactive approval workflow
|
159
|
+
|
160
|
+
If you do not want to manually create sessions and handle each state manually,
|
161
|
+
you can use the interactive approval workflow using
|
162
|
+
[Cased::CLI::InteractiveSession](https://github.com/cased/cased-ruby/blob/3b0c8ebd37ba7deb83236be7dba4d52c74d7e4e5/lib/cased/cli/interactive_session.rb).
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
Cased.configure do |config|
|
166
|
+
config.guard_application_key = 'guard_application_1pG43HF3aRHjNTTm10zzu0tngBO'
|
167
|
+
end
|
168
|
+
|
169
|
+
session = Cased::CLI::InteractiveSession.start
|
170
|
+
|
171
|
+
if session.approved?
|
172
|
+
github.issues.each do |issue|
|
173
|
+
puts issue.title
|
174
|
+
end
|
175
|
+
else
|
176
|
+
puts 'Unauthorized to export GitHub issues.'
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
180
|
+
You no longer need to handle obtaining the user token or asking for a reason up
|
181
|
+
front, `Cased::CLI::InteractiveSession` will prompt the user for any reason
|
182
|
+
being required as necessary.
|
183
|
+
|
184
|
+
### Audit trails
|
185
|
+
|
186
|
+
#### Publishing events to Cased
|
79
187
|
|
80
188
|
There are two ways to publish your first Cased event.
|
81
189
|
|
@@ -100,7 +208,7 @@ Cased.publish(
|
|
100
208
|
|
101
209
|
**Cased::Model**
|
102
210
|
|
103
|
-
cased-ruby provides a class mixin that gives you a framework to publish events.
|
211
|
+
`cased-ruby` provides a class mixin that gives you a framework to publish events.
|
104
212
|
|
105
213
|
```ruby
|
106
214
|
require 'cased-ruby'
|
@@ -170,9 +278,9 @@ Both examples above are equivelent in that they publish the following `credit_ca
|
|
170
278
|
}
|
171
279
|
```
|
172
280
|
|
173
|
-
|
281
|
+
#### Retrieving events from a Cased audit trail
|
174
282
|
|
175
|
-
If you plan on retrieving events from your audit
|
283
|
+
If you plan on retrieving audit events from your Cased audit trail you must use a Cased API key.
|
176
284
|
|
177
285
|
```ruby
|
178
286
|
require 'cased-ruby'
|
@@ -193,31 +301,9 @@ query.success? # => true
|
|
193
301
|
query.error? # => false
|
194
302
|
```
|
195
303
|
|
196
|
-
|
197
|
-
|
198
|
-
Cased policies allow you to filter events by providing variables to your Cased Policy events query. One example of a Cased Policy is to have a single Cased Policy that you can use to query events for any user in your database without having to create a Cased Policy for each user.
|
199
|
-
|
200
|
-
```ruby
|
201
|
-
require 'cased-ruby'
|
202
|
-
|
203
|
-
Cased.configure do |config|
|
204
|
-
config.policy_key = 'policy_live_1dQpY5JliYgHSkEntAbMVzuOROh'
|
205
|
-
end
|
206
|
-
|
207
|
-
variables = {
|
208
|
-
user_id: 'user_1dSHQSNtAH90KA8zGTooMnmMdiD',
|
209
|
-
}
|
210
|
-
query = Cased.policy(variables: variables).events.limit(25).page(1)
|
211
|
-
results = query.results
|
212
|
-
results.each do |event|
|
213
|
-
puts event['action'] # => credit_card.charge
|
214
|
-
puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
|
215
|
-
end
|
216
|
-
```
|
217
|
-
|
218
|
-
### Retrieving events from multiple Cased Policies
|
304
|
+
#### Retrieving events from multiple Cased audit trails
|
219
305
|
|
220
|
-
To retrieve events from one or more Cased
|
306
|
+
To retrieve audit events from one or more Cased audit trails you can configure multiple Cased Policy API keys and retrieve events for each one.
|
221
307
|
|
222
308
|
```ruby
|
223
309
|
require 'cased-ruby'
|
@@ -229,14 +315,14 @@ Cased.configure do |config|
|
|
229
315
|
}
|
230
316
|
end
|
231
317
|
|
232
|
-
query = Cased.
|
318
|
+
query = Cased.policies[:users].events.limit(25).page(1)
|
233
319
|
results = query.results
|
234
320
|
results.each do |event|
|
235
321
|
puts event['action'] # => user.login
|
236
322
|
puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
|
237
323
|
end
|
238
324
|
|
239
|
-
query = Cased.
|
325
|
+
query = Cased.policies[:organizations].events.limit(25).page(1)
|
240
326
|
results = query.results
|
241
327
|
results.each do |event|
|
242
328
|
puts event['action'] # => organization.create
|
@@ -244,9 +330,9 @@ results.each do |event|
|
|
244
330
|
end
|
245
331
|
```
|
246
332
|
|
247
|
-
|
333
|
+
#### Exporting events
|
248
334
|
|
249
|
-
Exporting events from
|
335
|
+
Exporting events from Cased allows you to provide users with exports of their own data or to respond to data requests.
|
250
336
|
|
251
337
|
```ruby
|
252
338
|
require 'cased-ruby'
|
@@ -262,7 +348,7 @@ export = Cased.policy.exports.create(
|
|
262
348
|
export.download_url # => https://api.cased.com/exports/export_1dSHQSNtAH90KA8zGTooMnmMdiD/download?token=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoidXNlcl8xZFFwWThiQmdFd2RwbWRwVnJydER6TVg0ZkgiLCJ
|
263
349
|
```
|
264
350
|
|
265
|
-
|
351
|
+
#### Masking & filtering sensitive information
|
266
352
|
|
267
353
|
If you are handling sensitive information on behalf of your users you should consider masking or filtering any sensitive information.
|
268
354
|
|
@@ -279,23 +365,18 @@ Cased.publish(
|
|
279
365
|
)
|
280
366
|
```
|
281
367
|
|
282
|
-
|
368
|
+
#### Console Usage
|
283
369
|
|
284
|
-
Most Cased events will be created by users from actions on the website from
|
285
|
-
custom defined events or lifecycle callbacks. The exception is any console
|
286
|
-
session where models may generate Cased events as you start to modify records.
|
370
|
+
Most Cased events will be created by users from actions on the website from custom defined events or lifecycle callbacks. The exception is any console session where models may generate Cased events as you start to modify records.
|
287
371
|
|
288
|
-
By default any console session will include the hostname of where the console
|
289
|
-
session takes place. Since every event must have an actor, you must set the
|
290
|
-
actor at the beginning of your console session. If you don't know the user,
|
291
|
-
it's recommended you create a system/robot user.
|
372
|
+
By default any console session will include the hostname of where the console session takes place. Since every event must have an actor, you must set the actor at the beginning of your console session. If you don't know the user, it's recommended you create a system/robot user.
|
292
373
|
|
293
374
|
```ruby
|
294
375
|
# OTHER CONSOLE INITIALIZATION HERE
|
295
376
|
Cased.context.push(actor: @actor)
|
296
377
|
```
|
297
378
|
|
298
|
-
|
379
|
+
#### Disable publishing events
|
299
380
|
|
300
381
|
Although rare, there may be times where you wish to disable publishing events to Cased. To do so wrap your transaction inside of a `Cased.disable` block:
|
301
382
|
|
@@ -311,7 +392,7 @@ Or you can configure the entire process to disable publishing events.
|
|
311
392
|
CASED_DISABLE_PUBLISHING=1 bundle exec ruby crawl.rb
|
312
393
|
```
|
313
394
|
|
314
|
-
|
395
|
+
#### Context
|
315
396
|
|
316
397
|
One of the most easiest ways to publish detailed events to Cased is to push contextual information on to the Cased context.
|
317
398
|
|
@@ -366,7 +447,7 @@ To clear/reset the context:
|
|
366
447
|
Cased.context.clear
|
367
448
|
```
|
368
449
|
|
369
|
-
|
450
|
+
#### Testing
|
370
451
|
|
371
452
|
cased-ruby provides a test helper class that you can use to test events are being published to Cased.
|
372
453
|
|
@@ -417,7 +498,7 @@ class CreditCardTest < Test::Unit::TestCase
|
|
417
498
|
end
|
418
499
|
```
|
419
500
|
|
420
|
-
|
501
|
+
### Customizing cased-ruby
|
421
502
|
|
422
503
|
Out of the box cased-ruby takes care of serializing objects for you to the best of its ability, but you can customize cased-ruby should you like to fit your products needs.
|
423
504
|
|
data/bin/cli
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'cased-ruby'
|
6
|
+
|
7
|
+
Cased.configure do |config|
|
8
|
+
config.guard_application_key = 'guard_application_1oFqltbMqSEtJQKRCAYQNrQoXsS'
|
9
|
+
config.guard_deny_if_unreachable = true
|
10
|
+
end
|
11
|
+
|
12
|
+
Cased::CLI::InteractiveSession.start
|
13
|
+
|
14
|
+
puts 'Something destructive'
|
data/cased-ruby.gemspec
CHANGED
@@ -33,7 +33,9 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_dependency 'faraday', '~> 1.0'
|
34
34
|
spec.add_dependency 'faraday_middleware', '~> 1.0'
|
35
35
|
spec.add_dependency 'json', '~> 2'
|
36
|
+
spec.add_dependency 'jwt', '~> 2'
|
36
37
|
spec.add_dependency 'net-http-persistent', '~> 3.0'
|
38
|
+
spec.add_dependency 'subprocess', '~> 1.5.0'
|
37
39
|
spec.add_development_dependency 'bundler', '2.1.4'
|
38
40
|
spec.add_development_dependency 'byebug', '11.0.1'
|
39
41
|
spec.add_development_dependency 'minitest', '5.13.0'
|
data/lib/cased.rb
CHANGED
data/lib/cased/cli.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cased
|
4
|
+
module CLI
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'cased/cli/asciinema/writer'
|
9
|
+
require 'cased/cli/asciinema/file'
|
10
|
+
require 'cased/cli/recorder'
|
11
|
+
require 'cased/cli/log'
|
12
|
+
require 'cased/cli/session'
|
13
|
+
require 'cased/cli/interactive_session'
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Cased
|
6
|
+
module CLI
|
7
|
+
# Spec: https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md
|
8
|
+
module Asciinema
|
9
|
+
class File
|
10
|
+
OUT = 'o'
|
11
|
+
IN = 'i'
|
12
|
+
|
13
|
+
def self.from_writer(writer)
|
14
|
+
new(writer.header, writer.stream)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_cast(cast)
|
18
|
+
stream = cast.split("\n").collect do |data|
|
19
|
+
JSON.parse(data)
|
20
|
+
end
|
21
|
+
header = stream.shift
|
22
|
+
|
23
|
+
new(header, stream)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Required
|
27
|
+
attr_reader :header
|
28
|
+
attr_reader :version
|
29
|
+
attr_reader :width
|
30
|
+
attr_reader :height
|
31
|
+
attr_reader :stream
|
32
|
+
|
33
|
+
# Optional
|
34
|
+
attr_reader :timestamp
|
35
|
+
attr_reader :duration
|
36
|
+
attr_reader :idle_time_limit
|
37
|
+
attr_reader :command
|
38
|
+
attr_reader :title
|
39
|
+
attr_reader :env
|
40
|
+
attr_reader :theme
|
41
|
+
|
42
|
+
def initialize(header, stream)
|
43
|
+
@header = header
|
44
|
+
@version = header.fetch('version')
|
45
|
+
@width = header.fetch('width')
|
46
|
+
@height = header.fetch('height')
|
47
|
+
self.timestamp = header['timestamp']
|
48
|
+
self.duration = header['duration']
|
49
|
+
self.idle_time_limit = header['idle_time_limit']
|
50
|
+
@command = header['command']
|
51
|
+
@title = header['title']
|
52
|
+
@env = header.fetch('env', {})
|
53
|
+
@theme = header['theme']
|
54
|
+
@stream = stream
|
55
|
+
end
|
56
|
+
|
57
|
+
def timestamp=(new_timestamp)
|
58
|
+
@timestamp = case new_timestamp
|
59
|
+
when Integer
|
60
|
+
Time.at(new_timestamp)
|
61
|
+
when Time, NilClass
|
62
|
+
new_timestamp
|
63
|
+
else
|
64
|
+
raise ArgumentError, "unexpected timestamp format #{new_timestamp.class}, expected Integer, Time, or nil"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def duration=(new_duration)
|
69
|
+
@duration = case new_duration
|
70
|
+
when Float, NilClass
|
71
|
+
new_duration
|
72
|
+
else
|
73
|
+
raise ArgumentError, "unexpected duration format #{new_duration.class}, expected Float or nil"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def idle_time_limit=(new_idle_time_limit)
|
78
|
+
@idle_time_limit = case new_idle_time_limit
|
79
|
+
when Numeric, NilClass
|
80
|
+
new_idle_time_limit
|
81
|
+
else
|
82
|
+
raise ArgumentError, "unexpected idle_time_limit format #{new_idle_time_limit.class}, expected Integer, Float, or nil"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_cast
|
87
|
+
builder = []
|
88
|
+
builder << JSON.dump(header)
|
89
|
+
stream.each do |duration, type, data|
|
90
|
+
builder << JSON.dump([duration, type, data])
|
91
|
+
end
|
92
|
+
builder.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
str = []
|
97
|
+
stream.each do |_timestamp, type, data|
|
98
|
+
next unless type == OUT
|
99
|
+
|
100
|
+
str << data
|
101
|
+
end
|
102
|
+
|
103
|
+
str.join
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|