onetime-up 0.6.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: daf373c819502e6a34a5a85fe033e39323cec0d5136af81b394fcd597171601f
4
+ data.tar.gz: 9c5408c3eed4b30065a4093a0e2302fd41f96a127607feaef0e72200b534c3de
5
+ SHA512:
6
+ metadata.gz: a3149a2f9bfe3112ebcdcbaedabb184d42e0849781b589a8bfaf54a001b5f1b97437d922b59b31911c087563b2182f69761c4e1b34325637c9a0a4090132733d
7
+ data.tar.gz: 5032db644622b154dfd770a974befb924a9bed99c2f0548e3f4f1abf417a9296355b89b09b241d28f3ee645dfb69e1042205fd4abb6bf005bc3ac4819c87d12c
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ ## [0.6.0] - 2026-01-18
4
+
5
+ ### Added
6
+
7
+ Major/breaking changes:
8
+
9
+ - Upgrade to API v2
10
+ - Rename command "metadata" to "receipt"
11
+
12
+ Other changes:
13
+
14
+ - Remove Rakefile, signing data and Jeweler references
15
+ - Simplified and modernized gemspec (set minimum Ruby to 3.2)
16
+ - Add Gemfile
17
+ - Remove json gem dependency
18
+ - Api: Deduplicate any number of consecutive slashes
19
+ - Add RSpec and test suites
20
+ - Upgrade dependencies
21
+ - Update gem metadata and README following project rename
22
+ - Upgrade version, and simplify its handling
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011,2012 Delano Mandelbaum
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # Onetime-up
2
+
3
+ Fork of the Ruby program [`One-Time Secret`](https://github.com/onetimesecret/onetime-ruby), using the API v2.
4
+
5
+ See the original website for usage (commands are unchanged).
6
+
7
+ ## Breaking changes
8
+
9
+ The command `metadata` has been renamed `receipt` for consistency with the API.
data/bin/onetime ADDED
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/ruby
2
+
3
+ base_path = File.expand_path File.join(File.dirname(__FILE__), '..')
4
+ $:.unshift File.join(base_path, 'lib')
5
+
6
+ require 'uri'
7
+ require 'onetime/api'
8
+ require 'drydock'
9
+
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, @res['message']
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
+ @res = @api.get '/receipt/%s' % obj.argv.key
75
+ if @res.nil?
76
+ raise RuntimeError, 'Could not complete request'
77
+ elsif @api.response.code != 200
78
+ raise RuntimeError, @res['message']
79
+ end
80
+ case obj.global.format
81
+ when 'json'
82
+ puts @res.to_json
83
+ when 'yaml'
84
+ puts @res.to_yaml
85
+ else
86
+ puts @res.to_yaml
87
+ end
88
+ end
89
+
90
+ option :p, :passphrase, String, "Passphrase to decrypt the secret (only required if one was provided to you)"
91
+ argv :key
92
+ usage "onetime secret <KEY>"
93
+ usage "onetime secret [-p PASSPHRASE] <KEY>"
94
+ command :secret do |obj|
95
+ raise RuntimeError, "csv not supported" if obj.global.format == 'csv'
96
+ raise RuntimeError, "Usage: #{$0} secret <KEY>" unless obj.argv.key
97
+ opts = {}
98
+ opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
99
+ base_uri = URI.parse Onetime::API.base_uri
100
+ if obj.argv.key =~ /#{base_uri.hostname}\/secret\/([a-zA-Z0-9]+)/
101
+ obj.argv.key = $1
102
+ end
103
+ @res = @api.post '/secret/%s/reveal' % [obj.argv.key], opts
104
+ if @res.nil?
105
+ raise RuntimeError, 'Could not complete request'
106
+ elsif @api.response.code != 200
107
+ raise RuntimeError, @res['message']
108
+ end
109
+ case obj.global.format
110
+ when 'json'
111
+ puts @res.to_json
112
+ when 'yaml'
113
+ puts @res.to_yaml
114
+ else
115
+ value = @res['record'] && @res['record']['value']
116
+ puts value if value
117
+ end
118
+ end
119
+ command_alias :secret, :get
120
+
121
+ usage "onetime share"
122
+ usage "onetime share [-t 3600] [-p PASSPHRASE]"
123
+ usage "echo 'your secret' | onetime share"
124
+ usage "<path/2/file onetime share"
125
+ option :t, :ttl, Integer, "Time-to-live in seconds"
126
+ option :p, :passphrase, String, "Passphrase to encrypt the secret (something only you and recipient know)"
127
+ option :r, :recipient, Array, "Email address to deliver the secret link"
128
+ command :share do |obj|
129
+ recipients = [obj.option.recipient, obj.global.recipient].flatten.compact.uniq
130
+ begin
131
+ if Kernel.select [$stdin], nil, nil, 0
132
+ secret_value = STDIN.read
133
+ else
134
+ STDERR.puts "Paste message here (hit control-D to continue):"
135
+ secret_value = ARGF.read
136
+ STDERR.puts # new line to let the person know we got it.
137
+ end
138
+ rescue Interrupt => ex
139
+ puts "Exiting..."
140
+ exit 0
141
+ end
142
+ raise RuntimeError, "No secret provided" if secret_value.chomp.empty?
143
+ opts = { :secret => secret_value, :ttl => obj.option.ttl, :recipient => recipients }
144
+ opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
145
+ @res = @api.post '/secret/conceal', opts
146
+ if @res.nil?
147
+ raise RuntimeError, 'Could not complete request'
148
+ elsif @api.response.code != 200
149
+ raise RuntimeError, @res['message']
150
+ end
151
+ secret_key = @res['record']['secret']['key']
152
+ uri = OT::API.web_uri('secret', secret_key)
153
+ case obj.global.format
154
+ when 'json'
155
+ puts @res.to_json
156
+ when 'yaml'
157
+ puts @res.to_yaml
158
+ else
159
+ recipient = @res['details']['recipient']
160
+ if recipient && !recipient.compact.empty?
161
+ STDERR.puts '# Secret link sent to: %s' % recipient.join(',')
162
+ else
163
+ puts uri
164
+ end
165
+ end
166
+ end
167
+
168
+ usage "onetime generate"
169
+ usage "onetime generate [-t 3600] [-p PASSPHRASE]"
170
+ option :t, :ttl, Integer, "Time-to-live in seconds"
171
+ option :p, :passphrase, String, "Passphrase to encrypt the secret (something only you and recipient know)"
172
+ option :r, :recipient, Array, "Email address to deliver the secret link"
173
+ command :generate do |obj|
174
+ recipients = [obj.option.recipient, obj.global.recipient].flatten.compact.uniq
175
+ opts = { :ttl => obj.option.ttl, :recipient => recipients }
176
+ opts[:passphrase] = obj.option.passphrase if obj.option.passphrase
177
+ @res = @api.post '/secret/generate', opts
178
+ if @res.nil?
179
+ raise RuntimeError, 'Could not complete request'
180
+ elsif @api.response.code != 200
181
+ raise RuntimeError, @res['message']
182
+ end
183
+ secret_key = @res['record']['secret']['key']
184
+ uri = OT::API.web_uri('secret', secret_key)
185
+ case obj.global.format
186
+ when 'json'
187
+ puts @res.to_json
188
+ when 'yaml'
189
+ puts @res.to_yaml
190
+ when 'csv'
191
+ puts uri
192
+ else
193
+ recipient = @res['details']['recipient']
194
+ if recipient && !recipient.compact.empty?
195
+ STDERR.puts '# Secret link sent to: %s' % recipient.join(',')
196
+ else
197
+ puts uri
198
+ end
199
+ end
200
+ end
201
+
202
+ end
203
+ end
204
+
205
+ begin
206
+ Drydock.run! ARGV, STDIN
207
+ rescue RuntimeError => ex
208
+ STDERR.puts ex.message
209
+ exit 1
210
+ rescue => ex
211
+ puts ex.message
212
+ puts ex.backtrace
213
+ exit 1
214
+ end
@@ -0,0 +1,134 @@
1
+
2
+
3
+ require 'httparty'
4
+ require 'uri'
5
+ require_relative 'version'
6
+
7
+ begin
8
+ require 'yajl-ruby'
9
+ rescue LoadError => ex
10
+ require 'json'
11
+ end
12
+
13
+ begin
14
+ require 'yaml'
15
+ rescue LoadError => ex
16
+ end
17
+
18
+
19
+ # Onetime::API - v0.3
20
+ #
21
+ # A basic client library for the onetimesecret.com API.
22
+ #
23
+ # Usage:
24
+ #
25
+ # api = OT::API.new 'delano@onetimesecret.com', '4eb33c6340006d6607c813fc7e707a32f8bf5342'
26
+ #
27
+ # api.get '/status'
28
+ # # => {'status' => 'nominal'}
29
+ #
30
+ # api.post '/generate', :passphrase => 'yourspecialpassphrase'
31
+ # # => {'value' => '3Rg8R2sfD3?a', 'metadata_key' => '...', 'secret_key' => '...'}
32
+ #
33
+ module Onetime
34
+ class API
35
+ unless defined?(Onetime::API::HOME)
36
+ HOME = File.expand_path File.join(File.dirname(__FILE__), '..', '..')
37
+ end
38
+ end
39
+ class API
40
+ include HTTParty
41
+ base_uri 'https://eu.onetimesecret.com/api'
42
+ format :json
43
+ headers 'X-Onetime-Client' => 'ruby: %s/%s' % [RUBY_VERSION, Onetime::VERSION]
44
+ attr_reader :opts, :response, :custid, :key, :default_params, :anonymous
45
+ def initialize custid=nil, key=nil, opts={}
46
+ unless ENV['ONETIME_HOST'].to_s.empty?
47
+ self.class.base_uri ENV['ONETIME_HOST']
48
+ end
49
+ @opts = opts
50
+ @default_params = {}
51
+ @custid = custid || ENV['ONETIME_CUSTID']
52
+ @key = key || ENV['ONETIME_APIKEY']
53
+ if @custid.to_s.empty? && @key.to_s.empty?
54
+ @anonymous = true
55
+ elsif @custid.to_s.empty? || @key.to_s.empty?
56
+ raise RuntimeError, "You provided a custid without an apikey" if @key.to_s.empty?
57
+ raise RuntimeError, "You provided an apikey without a custid" if @custid.to_s.empty?
58
+ else
59
+ @anonymous = false
60
+ opts[:basic_auth] ||= { :username => @custid, :password => @key }
61
+ end
62
+ end
63
+ def get path, params=nil
64
+ opts = self.opts.clone
65
+ opts[:query] = (params || {}).merge default_params
66
+ execute_request :get, path, opts
67
+ end
68
+ def post path, params=nil
69
+ opts = self.opts.clone
70
+ body_params = (params || {}).merge default_params
71
+
72
+ # V2 API uses JSON format
73
+ opts[:headers] = (opts[:headers] || {}).merge({
74
+ 'Content-Type' => 'application/json',
75
+ 'Accept' => 'application/json'
76
+ })
77
+
78
+ # Only /secret/conceal and /secret/generate wrap params in "secret" key
79
+ # Other endpoints (reveal, burn, etc.) do NOT wrap
80
+ if path =~ /\/secret\/(conceal|generate)$/
81
+ body_params = { secret: body_params }
82
+ end
83
+
84
+ opts[:body] = body_params.to_json
85
+
86
+ execute_request :post, path, opts
87
+ end
88
+ def api_path *args
89
+ args.unshift ['', 'v2'] # force leading slash and v2 version
90
+ path = args.flatten.join('/')
91
+ path.gsub(/\/+/, '/')
92
+ end
93
+ private
94
+ def execute_request meth, path, opts
95
+ path = api_path [path]
96
+ @response = self.class.send meth, path, opts
97
+ result = self.class.indifferent_params @response.parsed_response
98
+ result
99
+ end
100
+ class << self
101
+ def web_uri *args
102
+ uri = URI.parse(OT::API.base_uri)
103
+ uri.path = web_path *args
104
+ uri
105
+ end
106
+ def web_path *args
107
+ args.unshift [''] # force leading slash
108
+ path = args.flatten.join('/')
109
+ path.gsub(/\/+/, '/')
110
+ end
111
+ def indifferent_params(params)
112
+ if params.is_a?(Hash)
113
+ params = indifferent_hash.merge(params)
114
+ params.each do |key, value|
115
+ next unless value.is_a?(Hash) || value.is_a?(Array)
116
+ params[key] = indifferent_params(value)
117
+ end
118
+ elsif params.is_a?(Array)
119
+ params.collect! do |value|
120
+ if value.is_a?(Hash) || value.is_a?(Array)
121
+ indifferent_params(value)
122
+ else
123
+ value
124
+ end
125
+ end
126
+ end
127
+ end
128
+ def indifferent_hash
129
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
130
+ end
131
+ end
132
+ end
133
+ end
134
+ OT = Onetime unless defined?(OT)
@@ -0,0 +1,3 @@
1
+ module Onetime
2
+ VERSION = "0.6.0"
3
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: onetime-up
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Delano Mandelbaum
8
+ - Saverio Miroddi
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 1980-01-02 00:00:00.000000000 Z
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
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.24.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.24.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: A Ruby library and command-line tool for sharing secrets securely using
70
+ the onetimesecret.com API. Create and retrieve one-time secret links for sensitive
71
+ information.
72
+ email:
73
+ - delano@onetimesecret.com
74
+ - saverio.pub2@gmail.com
75
+ executables:
76
+ - onetime
77
+ extensions: []
78
+ extra_rdoc_files: []
79
+ files:
80
+ - CHANGELOG.md
81
+ - LICENSE.txt
82
+ - README.md
83
+ - bin/onetime
84
+ - lib/onetime/api.rb
85
+ - lib/onetime/version.rb
86
+ homepage: https://github.com/onetimesecret/onetime-ruby-up
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ source_code_uri: https://github.com/onetimesecret/onetime-ruby-up
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '3.2'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.0.0
104
+ requirements: []
105
+ rubygems_version: 3.6.7
106
+ specification_version: 4
107
+ summary: Command-line tool and library for onetimesecret.com API (API v2)
108
+ test_files: []