konfidant 0.7.0 → 1.4.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 +4 -4
- data/LICENSE +21 -0
- data/README.md +125 -254
- data/lib/konfidant/client.rb +164 -94
- data/lib/konfidant/errors.rb +8 -1
- data/lib/konfidant/knf.rb +469 -0
- data/lib/konfidant/types.rb +24 -17
- data/lib/konfidant/version.rb +1 -1
- data/lib/konfidant.rb +1 -0
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2dd0f63c7378b463ca026143137aff868ad08b6e7d8b8a8672120fa283138326
|
|
4
|
+
data.tar.gz: 9b77783dc745eb9919f0bb864cd506899d2651b957af20da128639329797c5a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f704dc0b64fdb6820a0a9220f4bbb8abc876d402ee96bffdbac2b4187e53953528ae057661a57da014879ed2dfda51dda32dbc1684a25601b370ec8693d87037
|
|
7
|
+
data.tar.gz: 5f266d4494ae32900e035b0b75d23150441c9630f006fb6d22263ad7e4edf61736d59e793ea333b82953ffa217b74954dba2dc0ab4545c73aff52be249415571
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Konfidant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -3,32 +3,38 @@
|
|
|
3
3
|
[](https://github.com/konfidant/sdk-ruby/actions/workflows/test.yml)
|
|
4
4
|
[](https://app.codacy.com/gh/konfidant/sdk-ruby/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
5
5
|
[](https://app.codacy.com/gh/konfidant/sdk-ruby/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
|
|
6
|
+
[](https://sonarcloud.io/summary/new_code?id=konfidant_sdk-ruby)
|
|
6
7
|
|
|
7
|
-
Official Ruby SDK for the [Konfidant](https://www.konfidant.app) API.
|
|
8
|
+
Official Ruby SDK for the [Konfidant](https://www.konfidant.app?utm_source=github&utm_medium=rubysdk&utm_campaign=github) API.
|
|
8
9
|
|
|
9
|
-
Konfidant lets you share secrets —
|
|
10
|
+
Konfidant lets you share secrets — text and files — that self-destruct after being read.
|
|
11
|
+
|
|
12
|
+
## Zero-knowledge model
|
|
13
|
+
|
|
14
|
+
All content is **encrypted on your machine** before anything is sent:
|
|
15
|
+
|
|
16
|
+
- Every share gets a fresh random 256-bit key. Text, file bytes, file name and MIME type are encrypted together
|
|
17
|
+
with AES-256-GCM in the chunked KNF1
|
|
18
|
+
format (stdlib `OpenSSL` only).
|
|
19
|
+
- Konfidant receives only ciphertext and its size. It never sees the key, the content or the file name.
|
|
20
|
+
- The key lives **only in the share link's URL fragment**: `https://download.konfidant.app/#t=<token>&k=<key>`.
|
|
21
|
+
Browsers never send the fragment to a server. The `t` token is single-use, so the ciphertext can be fetched once.
|
|
22
|
+
- Anyone holding the full `share_url` can read the secret once — treat it like the secret itself. If you lose it,
|
|
23
|
+
the content cannot be recovered by anyone, including Konfidant.
|
|
10
24
|
|
|
11
25
|
---
|
|
12
26
|
|
|
13
27
|
## Installation
|
|
14
28
|
|
|
15
|
-
Add to your `Gemfile`:
|
|
16
|
-
|
|
17
29
|
```ruby
|
|
18
30
|
gem 'konfidant'
|
|
19
31
|
```
|
|
20
32
|
|
|
21
|
-
Then run:
|
|
22
|
-
|
|
23
33
|
```bash
|
|
24
|
-
bundle install
|
|
34
|
+
bundle install # or: gem install konfidant
|
|
25
35
|
```
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
gem install konfidant
|
|
31
|
-
```
|
|
37
|
+
Requires Ruby >= 3.2. No runtime dependencies (stdlib `net/http`, `openssl`, `json`).
|
|
32
38
|
|
|
33
39
|
---
|
|
34
40
|
|
|
@@ -37,307 +43,172 @@ gem install konfidant
|
|
|
37
43
|
```ruby
|
|
38
44
|
require 'konfidant'
|
|
39
45
|
|
|
40
|
-
client = Konfidant::Client.new(api_key: '
|
|
41
|
-
|
|
42
|
-
result = client.share_text(text: 'super-secret-password', ttl_hours: 24)
|
|
43
|
-
|
|
44
|
-
puts "Share this link: #{result.share_url}"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Authentication
|
|
46
|
+
client = Konfidant::Client.new(api_key: ENV['KONFIDANT_API_KEY'])
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
text = client.share_text(text: 'db-password: hunter2', ttl_hours: 24)
|
|
49
|
+
puts text.share_url
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
client
|
|
51
|
+
file = File.open('contract.pdf', 'rb') do |f|
|
|
52
|
+
client.share_file(content: f, filename: 'contract.pdf', content_type: 'application/pdf', ttl_hours: 48)
|
|
53
|
+
end
|
|
54
|
+
puts file.share_url
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
## API
|
|
59
|
+
## API reference
|
|
60
60
|
|
|
61
|
-
### `Konfidant::Client.new`
|
|
61
|
+
### `Konfidant::Client.new(api_key:, base_url: nil, http_timeout: 120)`
|
|
62
62
|
|
|
63
63
|
| Option | Type | Required | Description |
|
|
64
64
|
|----------------|-----------|----------|----------------------------------------------------------------------|
|
|
65
|
-
| `api_key` | `String` | Yes | Your Konfidant API key
|
|
66
|
-
| `base_url` | `String` | No | Override the base URL (default: `https://www.konfidant.app`)
|
|
65
|
+
| `api_key` | `String` | Yes | Your Konfidant API key (sent as `Authorization: Bearer …`) |
|
|
66
|
+
| `base_url` | `String` | No | Override the API base URL (default: `https://www.konfidant.app`) |
|
|
67
67
|
| `http_timeout` | `Integer` | No | Per-request HTTP timeout in seconds (default: `120`; `nil` disables) |
|
|
68
68
|
|
|
69
69
|
Raises `ArgumentError` if `api_key` is nil or empty.
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### `client.share_text(text:, ttl_hours:)`
|
|
74
|
-
|
|
75
|
-
Encrypt and share a text message.
|
|
76
|
-
|
|
77
|
-
| Argument | Type | Description |
|
|
78
|
-
|-------------|-----------|--------------------------|
|
|
79
|
-
| `text` | `String` | The secret text to share |
|
|
80
|
-
| `ttl_hours` | `Integer` | Time-to-live in hours |
|
|
81
|
-
|
|
82
|
-
Returns a `Konfidant::ShareTextResponse`:
|
|
83
|
-
|
|
84
|
-
| Field | Type | Description |
|
|
85
|
-
|----------------|-----------|---------------------------------------------|
|
|
86
|
-
| `text_id` | `String` | Unique ID of the shared text |
|
|
87
|
-
| `share_url` | `String` | One-time download link to send to recipient |
|
|
88
|
-
| `expires_at` | `String` | Expiry datetime |
|
|
89
|
-
| `verified_burn`| `Boolean` | Whether burn-on-read is verified |
|
|
90
|
-
|
|
91
|
-
#### Example: share text
|
|
92
|
-
|
|
93
|
-
```ruby
|
|
94
|
-
result = client.share_text(text: 'db-password: hunter2', ttl_hours: 48)
|
|
95
|
-
|
|
96
|
-
puts result.share_url # send to recipient
|
|
97
|
-
puts result.expires_at
|
|
98
|
-
puts result.verified_burn
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
### `client.share_file(filename:, file_size:, ttl_hours:)`
|
|
71
|
+
### `client.share_text(text:, ttl_hours: nil)` → `Konfidant::TextShare`
|
|
104
72
|
|
|
105
|
-
|
|
106
|
-
the
|
|
73
|
+
Encrypts `text` (UTF-8, no SDK-side size limit; your plan's limit applies server-side) and uploads the ciphertext.
|
|
74
|
+
`ttl_hours` is omitted from the request when `nil` (server default applies).
|
|
107
75
|
|
|
108
|
-
|
|
76
|
+
| Field | Type | Description |
|
|
77
|
+
|--------------|---------------|------------------------------------------------|
|
|
78
|
+
| `share_url` | `String` | One-time link **including the key** (`&k=…`) |
|
|
79
|
+
| `text_id` | `String, nil` | Text ID (`nil` when verified burn is disabled) |
|
|
80
|
+
| `expires_at` | `String` | ISO 8601 expiry |
|
|
109
81
|
|
|
110
|
-
|
|
111
|
-
|-------------|-----------|----------------------------------|
|
|
112
|
-
| `filename` | `String` | Original filename with extension |
|
|
113
|
-
| `file_size` | `Integer` | File size in bytes |
|
|
114
|
-
| `ttl_hours` | `Integer` | Time-to-live in hours |
|
|
82
|
+
### `client.share_file(content:, filename:, content_type: '', ttl_hours: nil)` → `Konfidant::FileShare`
|
|
115
83
|
|
|
116
|
-
|
|
84
|
+
Encrypts and shares a file in one call: encrypt → `create_file_upload` → `upload_ciphertext` → `complete_file_upload`.
|
|
117
85
|
|
|
118
|
-
|
|
|
119
|
-
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
86
|
+
| Argument | Type | Description |
|
|
87
|
+
|----------------|--------------|-------------------------------------------------------------------------------------|
|
|
88
|
+
| `content` | `String, IO` | File bytes, or a readable IO. `File`/`StringIO` are streamed chunk by chunk; other IOs are read into memory |
|
|
89
|
+
| `filename` | `String` | Original file name, at most 1 024 UTF-8 bytes (encrypted) |
|
|
90
|
+
| `content_type` | `String` | MIME type, at most 255 bytes, may be empty (encrypted) |
|
|
91
|
+
| `ttl_hours` | `Integer` | Time-to-live in hours (optional) |
|
|
124
92
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
93
|
+
| Field | Type | Description |
|
|
94
|
+
|-----------------|---------------|----------------------------------------------|
|
|
95
|
+
| `share_url` | `String` | One-time link **including the key** (`&k=…`) |
|
|
96
|
+
| `file_id` | `String, nil` | File ID (`nil` when verified burn is off) |
|
|
97
|
+
| `expires_at` | `String` | ISO 8601 expiry |
|
|
98
|
+
| `verified_burn` | `Boolean` | Whether verified burn is enabled |
|
|
131
99
|
|
|
132
|
-
|
|
133
|
-
|----------------|-----------------------------|---------------------------------------|
|
|
134
|
-
| `io` | `IO` | Readable IO object (File, StringIO) |
|
|
135
|
-
| `size` | `Integer` | Content-Length in bytes |
|
|
136
|
-
| `content_type` | `String` | MIME type (e.g. `application/pdf`) |
|
|
137
|
-
| `presigned` | `Konfidant::ShareFileResponse` | Full response from `share_file` |
|
|
100
|
+
### Low-level file flow
|
|
138
101
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
#### Example: manual three-step flow
|
|
102
|
+
Use these when you need control over each step (e.g. your own retry logic).
|
|
142
103
|
|
|
143
104
|
```ruby
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# Step 1 – get presigned URL
|
|
148
|
-
presigned = client.share_file(
|
|
149
|
-
filename: 'report.pdf',
|
|
150
|
-
file_size: size,
|
|
151
|
-
ttl_hours: 72
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
# Step 2 – upload to S3
|
|
155
|
-
client.upload_file(
|
|
156
|
-
io: file,
|
|
157
|
-
size: size,
|
|
158
|
-
content_type: 'application/pdf',
|
|
159
|
-
presigned: presigned
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# Step 3 – poll for share link
|
|
163
|
-
loop do
|
|
164
|
-
status = client.get_file_status(presigned.file_key)
|
|
165
|
-
if status.status == 'complete'
|
|
166
|
-
puts "Share URL: #{status.share_url}"
|
|
167
|
-
break
|
|
168
|
-
end
|
|
169
|
-
sleep 2
|
|
170
|
-
end
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
### `client.get_file_status(file_key)`
|
|
176
|
-
|
|
177
|
-
Poll the encryption status of an uploaded file.
|
|
178
|
-
|
|
179
|
-
| Argument | Type | Description |
|
|
180
|
-
|------------|----------|-----------------------------------------------|
|
|
181
|
-
| `file_key` | `String` | The `file_key` from the `share_file` response |
|
|
182
|
-
|
|
183
|
-
Returns a `Konfidant::FileStatusResponse`:
|
|
184
|
-
|
|
185
|
-
| Field | Type | When set |
|
|
186
|
-
|----------------|-----------|-----------------------------------------|
|
|
187
|
-
| `status` | `String` | Always (`"processing"` or `"complete"`) |
|
|
188
|
-
| `message` | `String` | When `processing` |
|
|
189
|
-
| `file_id` | `String` | When `complete` |
|
|
190
|
-
| `file_name` | `String` | When `complete` |
|
|
191
|
-
| `share_url` | `String` | When `complete` |
|
|
192
|
-
| `expires_at` | `String` | When `complete` |
|
|
193
|
-
| `verified_burn`| `Boolean` | When `complete` |
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
### `client.list_shares(type: nil, status: nil, limit: nil, offset: nil)`
|
|
198
|
-
|
|
199
|
-
List all shares for the authenticated organization. All parameters are optional.
|
|
105
|
+
key = Konfidant::Knf.generate_key
|
|
106
|
+
encryptor = Konfidant::Knf.encryptor(key: key, content: File.open('a.zip', 'rb'), kind: 'file',
|
|
107
|
+
name: 'a.zip', mime: 'application/zip')
|
|
200
108
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
| `status` | `String` | `"active"` or `"accessed"` |
|
|
205
|
-
| `limit` | `Integer`| Page size (default 50) |
|
|
206
|
-
| `offset` | `Integer`| Pagination offset |
|
|
109
|
+
upload = client.create_file_upload(ciphertext_size: encryptor.size, ttl_hours: 24)
|
|
110
|
+
client.upload_ciphertext(upload: upload, ciphertext: encryptor) # String or IO-like
|
|
111
|
+
done = client.complete_file_upload(file_key: upload.file_key)
|
|
207
112
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
| Field | Type | Description |
|
|
211
|
-
|--------------|----------------------------|---------------------|
|
|
212
|
-
| `shares` | `Array<Konfidant::Share>` | Share entries |
|
|
213
|
-
| `pagination` | `Konfidant::Pagination` | Page metadata |
|
|
214
|
-
|
|
215
|
-
Each `Konfidant::Share`:
|
|
216
|
-
|
|
217
|
-
| Field | Type | Description |
|
|
218
|
-
|------------------|---------------|-------------------------|
|
|
219
|
-
| `type` | `String` | `"file"` or `"text"` |
|
|
220
|
-
| `file_name` | `String` | Filename or text label |
|
|
221
|
-
| `file_size_bytes`| `Integer` | Size in bytes |
|
|
222
|
-
| `created_at` | `String` | Creation datetime |
|
|
223
|
-
| `expires_at` | `String` | Expiry datetime |
|
|
224
|
-
| `accessed_at` | `String, nil` | Access datetime, or nil |
|
|
225
|
-
| `created_by` | `String` | Email of creator |
|
|
226
|
-
|
|
227
|
-
`Konfidant::Pagination`:
|
|
113
|
+
share_url = Konfidant::Knf.build_share_url(done.download_url, key)
|
|
114
|
+
```
|
|
228
115
|
|
|
229
|
-
|
|
|
230
|
-
|
|
231
|
-
| `
|
|
232
|
-
| `
|
|
233
|
-
| `
|
|
234
|
-
| `has_more` | `Boolean` | Whether more pages exist |
|
|
116
|
+
| Method | Request | Returns |
|
|
117
|
+
|-----------------------------------------------------|--------------------------------------------------|-----------------------------------------------------------------------------------------|
|
|
118
|
+
| `create_file_upload(ciphertext_size:, ttl_hours:)` | `POST /api/v1/files` | `FileUpload(upload_url, file_key, upload_headers, upload_expires_in, ciphertext_size)` |
|
|
119
|
+
| `upload_ciphertext(upload:, ciphertext:)` | `PUT upload_url` with exactly `upload_headers` | `nil`; never sends the API key |
|
|
120
|
+
| `complete_file_upload(file_key:)` | `POST /api/v1/files/{file_key}/complete` | `CompletedUpload(download_url, file_id, expires_at, verified_burn)` |
|
|
235
121
|
|
|
236
|
-
|
|
122
|
+
`complete_file_upload` raises `ApiError` with status `409` and message `upload_incomplete` if the PUT did not land.
|
|
123
|
+
`download_url` contains only the token — append the key with `Knf.build_share_url` before sending it to anyone.
|
|
237
124
|
|
|
238
|
-
|
|
239
|
-
result = client.list_shares(type: 'file', limit: 10)
|
|
125
|
+
### `client.open_share(share_url)` → `Konfidant::OpenedShare`
|
|
240
126
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
end
|
|
127
|
+
Recipient side. Sends only the token (`POST https://<link host>/api/download`, no API key, no decryption key),
|
|
128
|
+
receives the ciphertext and decrypts it locally. Opening a share **consumes it**.
|
|
244
129
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
130
|
+
| Field | Type | Description |
|
|
131
|
+
|--------|---------------|---------------------------------------------|
|
|
132
|
+
| `kind` | `String` | `"text"` or `"file"` |
|
|
133
|
+
| `name` | `String` | File name (`""` for text) |
|
|
134
|
+
| `mime` | `String` | MIME type (`""` for text) |
|
|
135
|
+
| `data` | `String` | Decrypted bytes (binary / ASCII-8BIT) |
|
|
136
|
+
| `text` | `String, nil` | UTF-8 text for text shares, otherwise `nil` |
|
|
248
137
|
|
|
249
|
-
|
|
138
|
+
Raises `ApiError` (`410`) if the share was already opened or has expired, `KnfError` if the ciphertext does not
|
|
139
|
+
authenticate (wrong key, modified or truncated data).
|
|
250
140
|
|
|
251
|
-
### `client.
|
|
141
|
+
### `client.list_shares(type: nil, status: nil, limit: nil, offset: nil)` → `Konfidant::ListSharesResponse`
|
|
252
142
|
|
|
253
|
-
|
|
143
|
+
| Argument | Type | Description |
|
|
144
|
+
|----------|-----------|----------------------------|
|
|
145
|
+
| `type` | `String` | `"file"` or `"text"` |
|
|
146
|
+
| `status` | `String` | `"active"` or `"accessed"` |
|
|
147
|
+
| `limit` | `Integer` | Page size (default 50) |
|
|
148
|
+
| `offset` | `Integer` | Pagination offset |
|
|
254
149
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
size: size,
|
|
259
|
-
filename: filename,
|
|
260
|
-
content_type: content_type,
|
|
261
|
-
ttl_hours: ttl_hours,
|
|
262
|
-
poll_interval: 2, # seconds between status checks (default: 2)
|
|
263
|
-
timeout: 60 # max wait for encryption in seconds (default: 60)
|
|
264
|
-
)
|
|
265
|
-
```
|
|
150
|
+
Returns `shares` (`Array<Konfidant::Share>` with `type`, `file_size_bytes`, `created_at`, `expires_at`,
|
|
151
|
+
`accessed_at`, `created_by`) and `pagination` (`total`, `limit`, `offset`, `has_more`). File names are not
|
|
152
|
+
available: the server never sees them.
|
|
266
153
|
|
|
267
|
-
|
|
268
|
-
|-----------------|-----------|---------|-------------------------------------|
|
|
269
|
-
| `io` | `IO` | — | Readable IO object (File, StringIO) |
|
|
270
|
-
| `size` | `Integer` | — | File size in bytes |
|
|
271
|
-
| `filename` | `String` | — | Filename with extension |
|
|
272
|
-
| `content_type` | `String` | — | MIME type |
|
|
273
|
-
| `ttl_hours` | `Integer` | — | Time-to-live in hours |
|
|
274
|
-
| `poll_interval` | `Numeric` | `2` | Seconds between status checks |
|
|
275
|
-
| `timeout` | `Numeric` | `60` | Max seconds to wait for encryption |
|
|
154
|
+
### `client.me` → `Konfidant::KeyInfo`
|
|
276
155
|
|
|
277
|
-
|
|
156
|
+
Describes the API key without creating a share: `organization` (`id`, `name`), `api_key` (`name`, `environment`,
|
|
157
|
+
`scopes`, `rate_limit_per_minute`, `expires_at`) and the plan's `limits` (`max_ttl_hours`, `max_file_size_mb`). It
|
|
158
|
+
needs no scope and does not count as an API share. Use it to check a key before storing it.
|
|
278
159
|
|
|
279
|
-
|
|
280
|
-
|----------------|-----------|--------------------------------|
|
|
281
|
-
| `share_url` | `String` | One-time download link |
|
|
282
|
-
| `file_id` | `String` | Unique file ID |
|
|
283
|
-
| `expires_at` | `String` | Expiry datetime |
|
|
284
|
-
| `verified_burn`| `Boolean` | Whether burn-on-read is active |
|
|
160
|
+
### `Konfidant::Knf`
|
|
285
161
|
|
|
286
|
-
|
|
287
|
-
within `timeout` seconds.
|
|
162
|
+
The KNF1 implementation is public for advanced use and interoperability:
|
|
288
163
|
|
|
289
|
-
|
|
164
|
+
| Method | Description |
|
|
165
|
+
|------------------------------------------------------------------------|-----------------------------------------------------|
|
|
166
|
+
| `generate_key` / `encode_key(key)` / `decode_key(str)` | 32-byte key; unpadded base64url (43 chars) |
|
|
167
|
+
| `encrypt(key:, content:, kind:, name: '', mime: '')` | Full ciphertext as a binary String |
|
|
168
|
+
| `encryptor(...)` | Streaming IO-like encryptor (`#read`, `#size`) |
|
|
169
|
+
| `encrypt_text(key:, text:)` | Text share ciphertext |
|
|
170
|
+
| `decrypt(key:, ciphertext:)` / `Decryptor.new(key:)#push`/`#finish` | Verify and decrypt (one-shot or streaming) |
|
|
171
|
+
| `ciphertext_size(metadata_length:, content_length:)` | Exact ciphertext length |
|
|
172
|
+
| `build_share_url(download_url, key)` / `parse_share_url(url)` | Share link helpers |
|
|
290
173
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
size = File.size('confidential.zip')
|
|
294
|
-
|
|
295
|
-
result = client.share_and_upload_file(
|
|
296
|
-
io: file,
|
|
297
|
-
size: size,
|
|
298
|
-
filename: 'confidential.zip',
|
|
299
|
-
content_type: 'application/zip',
|
|
300
|
-
ttl_hours: 48
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
puts "Ready to share: #{result.share_url}"
|
|
304
|
-
```
|
|
174
|
+
`encrypt` also accepts `chunk_size:` and a `nonce_prefix:` option that exists **only** for reproducing test
|
|
175
|
+
vectors — never pass `nonce_prefix` in production.
|
|
305
176
|
|
|
306
177
|
---
|
|
307
178
|
|
|
308
179
|
## Error handling
|
|
309
180
|
|
|
310
|
-
All
|
|
181
|
+
All SDK errors inherit from `Konfidant::Error`.
|
|
311
182
|
|
|
312
183
|
```ruby
|
|
313
184
|
begin
|
|
314
185
|
client.share_text(text: 'secret', ttl_hours: 1)
|
|
315
186
|
rescue Konfidant::ApiError => e
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
187
|
+
e.message # the "error" field of the JSON body, e.g. "upload_incomplete", or "HTTP 500"
|
|
188
|
+
e.status_code # e.g. 401
|
|
189
|
+
e.body # parsed body (Hash) or raw String
|
|
190
|
+
rescue Konfidant::KnfError => e
|
|
191
|
+
e.message # encryption/decryption failure
|
|
319
192
|
end
|
|
320
193
|
```
|
|
321
194
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
|
325
|
-
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
195
|
+
| Status | Meaning |
|
|
196
|
+
|--------|-------------------------------------------|
|
|
197
|
+
| `400` | Bad request / invalid body |
|
|
198
|
+
| `401` | Missing or invalid API key |
|
|
199
|
+
| `403` | Insufficient API key scope |
|
|
200
|
+
| `404` | Resource not found |
|
|
201
|
+
| `409` | `upload_incomplete` on complete |
|
|
202
|
+
| `410` | Share already opened or expired |
|
|
330
203
|
|
|
331
204
|
---
|
|
332
205
|
|
|
333
206
|
## Development
|
|
334
207
|
|
|
335
208
|
```bash
|
|
336
|
-
bundle install
|
|
337
|
-
bundle exec rspec
|
|
209
|
+
bundle install
|
|
210
|
+
bundle exec rspec
|
|
338
211
|
```
|
|
339
212
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
- Ruby >= 3.2.0
|
|
343
|
-
- No runtime dependencies (uses stdlib `net/http`, `uri`, `json`)
|
|
213
|
+
`spec/fixtures/knf1-test-vectors.json` holds the cross-SDK KNF1 test vectors; the specs reproduce every ciphertext
|
|
214
|
+
byte for byte.
|