onetime-up 0.6.2 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 829b100c0882cdb8e5f797d27d0f9e52e576cd20f20235f7836532f3872b74ea
4
- data.tar.gz: 9df7bd8e315d3fe6339619016b1b03c0450bbfb9c6a83644f1ce9bcf77e77fd6
3
+ metadata.gz: 4c1dc14a9677195dcc44ddb5f2f0ab15a310c2289a143d97aa2097d62e4f056f
4
+ data.tar.gz: ebb13a2e7050fffc000a18befa1d7ef456151a23f30d9dcc0d75b5ce084e20b6
5
5
  SHA512:
6
- metadata.gz: 905c34dd750efb26e2d3af6314d22b30d8a101885a9eef965d730a2c71849b80b54e6ddf6bad8f952c1de8a4a822b1df0f26667dc7b4cc883fec0efe25221d6d
7
- data.tar.gz: 53e8f305c78a4a79a539adb359508078835ae83f96156f8c9abd503ff7adce81d758411d86efffb30833eae46588ff5e8d6937dd316892020bc5291712d60f44
6
+ metadata.gz: 021a70dcfccc65e85f3510c02e620b351302275db33989571edb809af2956e359cbdfdf0254dd2128631c7c2751c2243b9663a97f1ee9443903cc6307ce252df
7
+ data.tar.gz: 44786b8cd1a188dd8fefa88766083da6fbb000de5d44465e66ed00832dc1334b3dab2e831b7bc065395a2a1fc138745fdeef0277d9f75353b78a7ca269b6cb16
data/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Onetime-up
2
2
 
3
- Fork of the Ruby program [`One-Time Secret`](https://github.com/onetimesecret/onetime-ruby), using the API v2.
3
+ Fork of the Ruby program [`One-Time Secret`](https://github.com/onetimesecret/onetime-ruby), using the API v2, with the following improvements:
4
+
5
+ - CLI built on Ruby stdlib — no third-party CLI dependency (the upstream `drydock` requirement has been removed)
6
+ - Uses the API v2 (response shapes updated accordingly)
7
+ - `share` accepts a positional file path (e.g. `onetime share /path/to/file`) in addition to stdin redirection
8
+ - `generate` rejects misuse (extra positional args, piped stdin) with a clear hint pointing at `onetime share`
9
+ - Default API host is `https://eu.onetimesecret.com/api`
10
+ - The `metadata` command is renamed `receipt` for consistency with the API
4
11
 
5
12
  ## Basic usage
6
13
 
@@ -8,12 +15,10 @@ Share a secret:
8
15
 
9
16
  ```sh
10
17
  echo "secret text" | onetime share
11
- ```
12
-
13
- Share a secret protected by a passphrase:
14
-
15
- ```sh
18
+ # Share a secret protected by a passphrase:
16
19
  echo "secret text" | onetime share -p "shared-passphrase"
20
+ # Share the contents of a local file:
21
+ onetime share /path/to/file
17
22
  ```
18
23
 
19
24
  Retrieve a secret:
@@ -42,3 +47,5 @@ The command `metadata` has been renamed `receipt` for consistency with the API.
42
47
  The default API host is now `https://eu.onetimesecret.com/api`.
43
48
 
44
49
  The library now uses API v2 response shapes. Programmatic callers should read receipt data from `record.receipt` and secret data from `record.secret` or reveal responses from `record.secret_value`.
50
+
51
+ The `generate` command now rejects extra positional arguments and piped stdin (previously both were silently ignored). Use `onetime share` to share file contents or piped data.
data/bin/onetime CHANGED
@@ -3,219 +3,6 @@
3
3
  base_path = File.expand_path File.join(File.dirname(__FILE__), '..')
4
4
  $:.unshift File.join(base_path, 'lib')
5
5
 
6
- require 'uri'
7
- require 'onetime/api'
8
- require 'drydock'
6
+ require 'onetime/cli'
9
7
 
10
- class Onetime::CLI
11
- class Definition
12
- extend Drydock
13
-
14
- default :share
15
-
16
- global :H, String, "Base URI (e.g. https://onetimesecret.com/api)"
17
- global :c, :custid, String, "Customer ID (e.g. you@yourcompany.com)"
18
- global :k, :apikey, String, "API key (e.g. 4eb33c6340006d6607c813fc7e707a32f8bf5342)"
19
-
20
- global :r, :recipient, Array, "Email address to deliver the secret link"
21
-
22
- global :f, :format, String, "Output format (json or yaml)"
23
- global :j, :json, "Shorthand for -f json"
24
- global :y, :yaml, "Shorthand for -f yaml"
25
- global :s, :string, "Shorthand for -f string (default)"
26
-
27
- global :D, :debug do
28
- OT::API.debug_output STDERR
29
- end
30
-
31
- global :V, :version do
32
- puts OT::VERSION
33
- exit 0
34
- end
35
-
36
- before do |obj|
37
- OT::API.base_uri obj.global.H if obj.global.H
38
- @api = OT::API.new obj.global.custid, obj.global.apikey
39
- obj.global.format = 'yaml' if obj.global.yaml
40
- obj.global.format = 'json' if obj.global.json
41
- obj.global.format = 'string' if obj.global.string
42
- obj.global.format = nil if obj.global.format == 'string'
43
- if obj.global.format && !['json', 'yaml', 'csv'].member?(obj.global.format)
44
- raise RuntimeError, "Unsupported format: #{obj.global.format}"
45
- end
46
- end
47
-
48
- usage "onetime status"
49
- command :status do |obj|
50
- @res = @api.get '/status'
51
- if @res.nil?
52
- raise RuntimeError, 'Could not complete request'
53
- elsif @api.response.code != 200
54
- raise RuntimeError, OT::API.response_error_message(@res)
55
- end
56
- case obj.global.format
57
- when 'json'
58
- puts @res.to_json
59
- when 'yaml'
60
- puts @res.to_yaml
61
- else
62
- msg = @api.anonymous ? 'Anonymous' : @api.custid
63
- STDERR.puts '# Host: %s' % OT::API.base_uri
64
- STDERR.puts '# Account: %s' % msg
65
- puts 'Service Status: %s' % @res[:status]
66
- end
67
- end
68
-
69
- argv :key
70
- usage "onetime receipt <KEY>"
71
- command :receipt do |obj|
72
- raise RuntimeError, "csv not supported" if obj.global.format == 'csv'
73
- raise RuntimeError, "Usage: #{$0} receipt <KEY>" unless obj.argv.key
74
-
75
- # Handle case where argv.key might be an array due to drydock parsing
76
- receipt_key = Array(obj.argv.key).first.to_s
77
-
78
- @res = @api.get '/receipt/%s' % receipt_key
79
- if @res.nil?
80
- raise RuntimeError, 'Could not complete request'
81
- elsif @api.response.code != 200
82
- raise RuntimeError, OT::API.response_error_message(@res)
83
- end
84
- case obj.global.format
85
- when 'json'
86
- puts @res.to_json
87
- when 'yaml'
88
- puts @res.to_yaml
89
- else
90
- puts @res.to_yaml
91
- end
92
- end
93
-
94
- option :p, :passphrase, String, "Passphrase to decrypt the secret (only required if one was provided to you)"
95
- argv :key
96
- usage "onetime secret <KEY>"
97
- usage "onetime secret [-p PASSPHRASE] <KEY>"
98
- command :secret do |obj|
99
- raise RuntimeError, "csv not supported" if obj.global.format == 'csv'
100
- raise RuntimeError, "Usage: #{$0} secret <KEY>" unless obj.argv.key
101
-
102
- # Handle case where argv.key might be an array due to drydock parsing
103
- secret_key = Array(obj.argv.key).first.to_s
104
-
105
- opts = { continue: true }
106
- opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
107
- secret_key = OT::API.extract_secret_key(secret_key)
108
- @res = @api.post '/secret/%s/reveal' % [secret_key], opts
109
- if @res.nil?
110
- raise RuntimeError, 'Could not complete request'
111
- elsif @api.response.code != 200
112
- raise RuntimeError, OT::API.response_error_message(@res)
113
- end
114
- case obj.global.format
115
- when 'json'
116
- puts @res.to_json
117
- when 'yaml'
118
- puts @res.to_yaml
119
- else
120
- value = @res.dig('record', 'secret_value')
121
- puts value if value
122
- end
123
- end
124
- command_alias :secret, :get
125
-
126
- usage "onetime share"
127
- usage "onetime share [-t 3600] [-p PASSPHRASE]"
128
- usage "echo 'your secret' | onetime share"
129
- usage "<path/2/file onetime share"
130
- option :t, :ttl, Integer, "Time-to-live in seconds"
131
- option :p, :passphrase, String, "Passphrase to encrypt the secret (something only you and recipient know)"
132
- option :r, :recipient, Array, "Email address to deliver the secret link"
133
- command :share do |obj|
134
- recipients = [obj.option.recipient, obj.global.recipient].flatten.compact.uniq
135
- begin
136
- if Kernel.select [$stdin], nil, nil, 0
137
- secret_value = STDIN.read
138
- else
139
- STDERR.puts "Paste message here (hit control-D to continue):"
140
- secret_value = ARGF.read
141
- STDERR.puts # new line to let the person know we got it.
142
- end
143
- rescue Interrupt => ex
144
- puts "Exiting..."
145
- exit 0
146
- end
147
- raise RuntimeError, "No secret provided" if secret_value.chomp.empty?
148
- opts = { :secret => secret_value, :ttl => obj.option.ttl, :recipient => recipients }
149
- opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
150
- @res = @api.post '/secret/conceal', opts
151
- if @res.nil?
152
- raise RuntimeError, 'Could not complete request'
153
- elsif @api.response.code != 200
154
- raise RuntimeError, OT::API.response_error_message(@res)
155
- end
156
- secret_key = OT::API.secret_key_from_response(@res)
157
- raise RuntimeError, 'Unexpected response: missing record.secret.key' unless secret_key
158
- uri = OT::API.web_uri('secret', secret_key)
159
- case obj.global.format
160
- when 'json'
161
- puts @res.to_json
162
- when 'yaml'
163
- puts @res.to_yaml
164
- else
165
- recipients = OT::API.recipients_from_response(@res)
166
- if !recipients.empty?
167
- STDERR.puts '# Secret link sent to: %s' % recipients.join(',')
168
- else
169
- puts uri
170
- end
171
- end
172
- end
173
-
174
- usage "onetime generate"
175
- usage "onetime generate [-t 3600] [-p PASSPHRASE]"
176
- option :t, :ttl, Integer, "Time-to-live in seconds"
177
- option :p, :passphrase, String, "Passphrase to encrypt the secret (something only you and recipient know)"
178
- option :r, :recipient, Array, "Email address to deliver the secret link"
179
- command :generate do |obj|
180
- recipients = [obj.option.recipient, obj.global.recipient].flatten.compact.uniq
181
- opts = { :ttl => obj.option.ttl, :recipient => recipients }
182
- opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
183
- @res = @api.post '/secret/generate', opts
184
- if @res.nil?
185
- raise RuntimeError, 'Could not complete request'
186
- elsif @api.response.code != 200
187
- raise RuntimeError, OT::API.response_error_message(@res)
188
- end
189
- secret_key = OT::API.secret_key_from_response(@res)
190
- raise RuntimeError, 'Unexpected response: missing record.secret.key' unless secret_key
191
- uri = OT::API.web_uri('secret', secret_key)
192
- case obj.global.format
193
- when 'json'
194
- puts @res.to_json
195
- when 'yaml'
196
- puts @res.to_yaml
197
- when 'csv'
198
- puts uri
199
- else
200
- recipients = OT::API.recipients_from_response(@res)
201
- if !recipients.empty?
202
- STDERR.puts '# Secret link sent to: %s' % recipients.join(',')
203
- else
204
- puts uri
205
- end
206
- end
207
- end
208
-
209
- end
210
- end
211
-
212
- begin
213
- Drydock.run! ARGV, STDIN
214
- rescue RuntimeError => ex
215
- STDERR.puts ex.message
216
- exit 1
217
- rescue => ex
218
- puts ex.message
219
- puts ex.backtrace
220
- exit 1
221
- end
8
+ exit Onetime::CLI.run(ARGV)
@@ -0,0 +1,134 @@
1
+ require 'optparse'
2
+
3
+ require_relative '../version'
4
+
5
+ module Onetime
6
+ module CLI
7
+ class Parser
8
+ class Error < StandardError; end
9
+
10
+ DEFAULT_COMMAND = 'share'.freeze
11
+ KNOWN_COMMANDS = %w[status receipt secret share generate].freeze
12
+ COMMAND_ALIASES = { 'get' => 'secret' }.freeze
13
+ VALID_FORMATS = %w[json yaml csv].freeze
14
+
15
+ COMMAND_OPTIONS = {
16
+ 'share' => %i[ttl passphrase recipient].freeze,
17
+ 'generate' => %i[ttl passphrase recipient].freeze,
18
+ 'secret' => %i[passphrase].freeze,
19
+ 'receipt' => [].freeze,
20
+ 'status' => [].freeze,
21
+ }.freeze
22
+
23
+ Result = Struct.new(
24
+ :command, :argv,
25
+ :base_uri, :custid, :apikey, :recipients,
26
+ :format, :debug, :show_version,
27
+ :ttl, :passphrase,
28
+ keyword_init: true,
29
+ )
30
+
31
+ def self.parse(argv)
32
+ new(argv).parse
33
+ end
34
+
35
+ def initialize(argv)
36
+ @argv = argv.dup
37
+ @base_uri = nil
38
+ @custid = nil
39
+ @apikey = nil
40
+ @global_recipients = []
41
+ @command_recipients = []
42
+ @format = nil
43
+ @debug = false
44
+ @show_version = false
45
+ @ttl = nil
46
+ @passphrase = nil
47
+ @yaml_flag = false
48
+ @json_flag = false
49
+ @string_flag = false
50
+ end
51
+
52
+ def parse
53
+ global_option_parser.order!(@argv)
54
+ command, rest = extract_command
55
+ if command
56
+ command_option_parser(command).order!(rest)
57
+ end
58
+ apply_format_precedence!
59
+ normalize_format!
60
+ Result.new(
61
+ command: command,
62
+ argv: rest,
63
+ base_uri: @base_uri,
64
+ custid: @custid,
65
+ apikey: @apikey,
66
+ recipients: (@command_recipients + @global_recipients).uniq,
67
+ format: @format,
68
+ debug: @debug,
69
+ show_version: @show_version,
70
+ ttl: @ttl,
71
+ passphrase: @passphrase,
72
+ )
73
+ rescue OptionParser::ParseError => e
74
+ raise Error, e.message
75
+ end
76
+
77
+ private
78
+
79
+ def global_option_parser
80
+ OptionParser.new do |opts|
81
+ opts.on('-H BASE_URI', String) { |v| @base_uri = v }
82
+ opts.on('-c CUSTID', '--custid CUSTID', String) { |v| @custid = v }
83
+ opts.on('-k APIKEY', '--apikey APIKEY', String) { |v| @apikey = v }
84
+ opts.on('-r RECIPIENT', '--recipient RECIPIENT', Array) { |v| @global_recipients.concat(Array(v)) }
85
+ opts.on('-f FORMAT', '--format FORMAT', String) { |v| @format = v }
86
+ opts.on('-j', '--json') { @json_flag = true }
87
+ opts.on('-y', '--yaml') { @yaml_flag = true }
88
+ opts.on('-s', '--string') { @string_flag = true }
89
+ opts.on('-D', '--debug') { @debug = true }
90
+ opts.on('-V', '--version') { @show_version = true }
91
+ end
92
+ end
93
+
94
+ def command_option_parser(command)
95
+ allowed = COMMAND_OPTIONS.fetch(command, [])
96
+ OptionParser.new do |opts|
97
+ if allowed.include?(:ttl)
98
+ opts.on('-t TTL', '--ttl TTL', Integer) { |v| @ttl = v }
99
+ end
100
+ if allowed.include?(:passphrase)
101
+ opts.on('-p PASSPHRASE', '--passphrase PASSPHRASE', String) { |v| @passphrase = v }
102
+ end
103
+ if allowed.include?(:recipient)
104
+ opts.on('-r RECIPIENT', '--recipient RECIPIENT', Array) { |v| @command_recipients.concat(Array(v)) }
105
+ end
106
+ end
107
+ end
108
+
109
+ def apply_format_precedence!
110
+ @format = 'yaml' if @yaml_flag
111
+ @format = 'json' if @json_flag
112
+ @format = 'string' if @string_flag
113
+ end
114
+
115
+ def normalize_format!
116
+ @format = nil if @format == 'string'
117
+ return if @format.nil?
118
+ return if VALID_FORMATS.include?(@format)
119
+ raise Error, "Unsupported format: #{@format}"
120
+ end
121
+
122
+ def extract_command
123
+ return [nil, []] if @show_version
124
+
125
+ raw = @argv.shift || DEFAULT_COMMAND
126
+ canonical = COMMAND_ALIASES.fetch(raw, raw)
127
+ unless KNOWN_COMMANDS.include?(canonical)
128
+ raise Error, "unknown command: #{raw}"
129
+ end
130
+ [canonical, @argv]
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,210 @@
1
+ require 'json'
2
+ require 'yaml'
3
+
4
+ require_relative '../api'
5
+ require_relative '../version'
6
+
7
+ module Onetime
8
+ module CLI
9
+ class Runner
10
+ class Error < StandardError; end
11
+
12
+ PROGRAM_NAME = 'onetime'.freeze
13
+
14
+ def initialize(parsed, stdin: $stdin, stdout: $stdout, stderr: $stderr)
15
+ @parsed = parsed
16
+ @stdin = stdin
17
+ @stdout = stdout
18
+ @stderr = stderr
19
+ end
20
+
21
+ def run
22
+ return print_version if @parsed.show_version
23
+
24
+ configure_api!
25
+ case @parsed.command
26
+ when 'status' then run_status
27
+ when 'receipt' then run_receipt
28
+ when 'secret' then run_secret
29
+ when 'share' then run_share
30
+ when 'generate' then run_generate
31
+ else
32
+ raise Error, "unhandled command: #{@parsed.command.inspect}"
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def print_version
39
+ @stdout.puts Onetime::VERSION
40
+ 0
41
+ end
42
+
43
+ def configure_api!
44
+ OT::API.base_uri @parsed.base_uri if @parsed.base_uri
45
+ OT::API.debug_output @stderr if @parsed.debug
46
+ @api = OT::API.new(@parsed.custid, @parsed.apikey)
47
+ end
48
+
49
+ def run_status
50
+ res = api_get('/status')
51
+ case @parsed.format
52
+ when 'json'
53
+ @stdout.puts res.to_json
54
+ when 'yaml'
55
+ @stdout.puts res.to_yaml
56
+ else
57
+ account = @api.anonymous ? 'Anonymous' : @api.custid
58
+ @stderr.puts '# Host: %s' % OT::API.base_uri
59
+ @stderr.puts '# Account: %s' % account
60
+ @stdout.puts 'Service Status: %s' % res[:status]
61
+ end
62
+ 0
63
+ end
64
+
65
+ def run_receipt
66
+ raise Error, 'csv not supported' if @parsed.format == 'csv'
67
+ raise Error, "Usage: #{PROGRAM_NAME} receipt <KEY>" if @parsed.argv.empty?
68
+
69
+ key = @parsed.argv.first.to_s
70
+ res = api_get('/receipt/%s' % key)
71
+ case @parsed.format
72
+ when 'json'
73
+ @stdout.puts res.to_json
74
+ else
75
+ @stdout.puts res.to_yaml
76
+ end
77
+ 0
78
+ end
79
+
80
+ def run_secret
81
+ raise Error, 'csv not supported' if @parsed.format == 'csv'
82
+ raise Error, "Usage: #{PROGRAM_NAME} secret <KEY>" if @parsed.argv.empty?
83
+
84
+ raw_key = @parsed.argv.first.to_s
85
+ key = OT::API.extract_secret_key(raw_key)
86
+ opts = { continue: true }
87
+ opts[:passphrase] = @parsed.passphrase if @parsed.passphrase
88
+ res = api_post('/secret/%s/reveal' % key, opts)
89
+ case @parsed.format
90
+ when 'json'
91
+ @stdout.puts res.to_json
92
+ when 'yaml'
93
+ @stdout.puts res.to_yaml
94
+ else
95
+ value = res.dig('record', 'secret_value')
96
+ @stdout.puts value if value
97
+ end
98
+ 0
99
+ end
100
+
101
+ def run_share
102
+ begin
103
+ secret_value = read_share_input
104
+ rescue Interrupt
105
+ @stdout.puts 'Exiting...'
106
+ return 0
107
+ end
108
+ raise Error, 'No secret provided' if secret_value.chomp.empty?
109
+
110
+ opts = { secret: secret_value, ttl: @parsed.ttl, recipient: @parsed.recipients }
111
+ opts[:passphrase] = @parsed.passphrase if @parsed.passphrase
112
+ res = api_post('/secret/conceal', opts)
113
+ emit_share_result(res)
114
+ 0
115
+ end
116
+
117
+ def run_generate
118
+ unless @parsed.argv.empty?
119
+ extras = @parsed.argv
120
+ raise Error, "generate takes no arguments (got: %s). Did you mean: onetime share < %s" % [extras.join(' '), extras.first]
121
+ end
122
+ if !@stdin.tty? && !@stdin.eof?
123
+ raise Error, 'generate does not read stdin. Did you mean: onetime share'
124
+ end
125
+ opts = { ttl: @parsed.ttl, recipient: @parsed.recipients }
126
+ opts[:passphrase] = @parsed.passphrase if @parsed.passphrase
127
+ res = api_post('/secret/generate', opts)
128
+ emit_generate_result(res)
129
+ 0
130
+ end
131
+
132
+ def read_share_input
133
+ if !@parsed.argv.empty?
134
+ read_argv_inputs(@parsed.argv)
135
+ elsif !@stdin.tty?
136
+ @stdin.read
137
+ else
138
+ @stderr.puts 'Paste message here (hit control-D to continue):'
139
+ content = @stdin.read
140
+ @stderr.puts
141
+ content
142
+ end
143
+ end
144
+
145
+ def read_argv_inputs(paths)
146
+ paths.map { |path| path == '-' ? @stdin.read : File.read(path) }.join
147
+ end
148
+
149
+ def emit_share_result(res)
150
+ secret_key = OT::API.secret_key_from_response(res)
151
+ raise Error, 'Unexpected response: missing record.secret.key' unless secret_key
152
+
153
+ uri = OT::API.web_uri('secret', secret_key)
154
+ case @parsed.format
155
+ when 'json'
156
+ @stdout.puts res.to_json
157
+ when 'yaml'
158
+ @stdout.puts res.to_yaml
159
+ else
160
+ recipients = OT::API.recipients_from_response(res)
161
+ if !recipients.empty?
162
+ @stderr.puts '# Secret link sent to: %s' % recipients.join(',')
163
+ else
164
+ @stdout.puts uri
165
+ end
166
+ end
167
+ end
168
+
169
+ def emit_generate_result(res)
170
+ secret_key = OT::API.secret_key_from_response(res)
171
+ raise Error, 'Unexpected response: missing record.secret.key' unless secret_key
172
+
173
+ uri = OT::API.web_uri('secret', secret_key)
174
+ case @parsed.format
175
+ when 'json'
176
+ @stdout.puts res.to_json
177
+ when 'yaml'
178
+ @stdout.puts res.to_yaml
179
+ when 'csv'
180
+ @stdout.puts uri
181
+ else
182
+ recipients = OT::API.recipients_from_response(res)
183
+ if !recipients.empty?
184
+ @stderr.puts '# Secret link sent to: %s' % recipients.join(',')
185
+ else
186
+ @stdout.puts uri
187
+ end
188
+ end
189
+ end
190
+
191
+ def api_get(path)
192
+ res = @api.get(path)
193
+ check_response!(res)
194
+ res
195
+ end
196
+
197
+ def api_post(path, params)
198
+ res = @api.post(path, params)
199
+ check_response!(res)
200
+ res
201
+ end
202
+
203
+ def check_response!(res)
204
+ raise Error, 'Could not complete request' if res.nil?
205
+ return if @api.response.code == 200
206
+ raise Error, OT::API.response_error_message(res)
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'api'
2
+ require_relative 'version'
3
+ require_relative 'cli/parser'
4
+ require_relative 'cli/runner'
5
+
6
+ module Onetime
7
+ module CLI
8
+ def self.run(argv, stdin: $stdin, stdout: $stdout, stderr: $stderr)
9
+ parsed = Parser.parse(argv)
10
+ Runner.new(parsed, stdin: stdin, stdout: stdout, stderr: stderr).run
11
+ rescue Parser::Error, Runner::Error, RuntimeError => e
12
+ stderr.puts e.message
13
+ 1
14
+ rescue StandardError => e
15
+ stdout.puts e.message
16
+ stdout.puts e.backtrace
17
+ 1
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,3 @@
1
1
  module Onetime
2
- VERSION = "0.6.2"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onetime-up
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -10,20 +10,6 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2026-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: drydock
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 1.0.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 1.0.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: httparty
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +68,9 @@ files:
82
68
  - README.md
83
69
  - bin/onetime
84
70
  - lib/onetime/api.rb
71
+ - lib/onetime/cli.rb
72
+ - lib/onetime/cli/parser.rb
73
+ - lib/onetime/cli/runner.rb
85
74
  - lib/onetime/version.rb
86
75
  homepage: https://github.com/onetimesecret/onetime-ruby-up
87
76
  licenses:
@@ -102,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
91
  - !ruby/object:Gem::Version
103
92
  version: 2.0.0
104
93
  requirements: []
105
- rubygems_version: 4.0.7
94
+ rubygems_version: 4.0.9
106
95
  specification_version: 4
107
96
  summary: Command-line tool and library for onetimesecret.com API (API v2)
108
97
  test_files: []