-
Notifications
You must be signed in to change notification settings - Fork 12
/
vss.proto
349 lines (303 loc) · 16.1 KB
/
vss.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
syntax = "proto3";
package vss;
option java_multiple_files = true;
option java_package = "org.vss";
// Request payload to be used for `GetObject` API call to server.
message GetObjectRequest {
// `store_id` is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single `store_id`.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the `store_id` level.
string store_id = 1;
// The key of the value to be fetched.
//
// If the specified `key` does not exist, returns `ErrorCode.NO_SUCH_KEY_EXCEPTION` in the
// the `ErrorResponse`.
//
// Consistency Guarantee:
// Get(read) operations against a `key` are consistent reads and will reflect all previous writes,
// since Put/Write provides read-after-write and read-after-update consistency guarantees.
//
// Read Isolation:
// Get/Read operations against a `key` are ensured to have read-committed isolation.
// Ref: https://en.wikipedia.org/wiki/Isolation_(database_systems)#Read_committed
string key = 2;
}
// Server response for `GetObject` API.
message GetObjectResponse {
// Fetched `value` and `version` along with the corresponding `key` in the request.
KeyValue value = 2;
}
// Request payload to be used for `PutObject` API call to server.
message PutObjectRequest {
// `store_id` is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single `store_id`.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the `store_id` level.
string store_id = 1;
// `global_version` is a sequence-number/version of the whole store. This can be used for versioning
// and ensures that multiple updates in case of multiple devices can only be done linearly, even
// if those updates did not directly conflict with each other based on keys/`transaction_items`.
//
// If present, the write will only succeed if the current server-side `global_version` against
// the `store_id` is same as in the request.
// Clients are expected to store (client-side) the global version against `store_id`.
// The request must contain their client-side value of `global_version` if global versioning and
// conflict detection is desired.
//
// For the first write of the store, global version should be '0'. If the write succeeds, clients
// must increment their global version (client-side) by 1.
// The server increments `global_version` (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. This updated global version
// should be used in subsequent `PutObjectRequest`s for the store.
//
// Requests with a conflicting version will fail with `CONFLICT_EXCEPTION` as ErrorCode.
optional int64 global_version = 2;
// Items to be written as a result of this `PutObjectRequest`.
//
// In an item, each `key` is supplied with its corresponding `value` and `version`.
// Clients can choose to encrypt the keys client-side in order to obfuscate their usage patterns.
// If the write is successful, the previous `value` corresponding to the `key` will be overwritten.
//
// Multiple items in `transaction_items` and `delete_items` of a single `PutObjectRequest` are written in
// a database-transaction in an all-or-nothing fashion.
// All Items in a single `PutObjectRequest` must have distinct keys.
//
// Key-level versioning (Conditional Write):
// Clients are expected to store a `version` against every `key`.
// The write will succeed if the current DB version against the `key` is the same as in the request.
// When initiating a `PutObjectRequest`, the request should contain their client-side `version`
// for that key-value.
//
// For the first write of any `key`, the `version` should be '0'. If the write succeeds, the client
// must increment their corresponding key versions (client-side) by 1.
// The server increments key versions (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. These updated key versions should
// be used in subsequent `PutObjectRequest`s for the keys.
//
// Requests with a conflicting/mismatched version will fail with `CONFLICT_EXCEPTION` as ErrorCode
// for conditional writes.
//
// Skipping key-level versioning (Non-conditional Write):
// If you wish to skip key-level version checks, set the `version` against the `key` to '-1'.
// This will perform a non-conditional write query, after which the `version` against the `key`
// is reset to '1'. Hence, the next `PutObjectRequest` for the `key` can be either
// a non-conditional write or a conditional write with `version` set to `1`.
//
// Considerations for transactions:
// Transaction writes of multiple items have a performance overhead, hence it is recommended to use
// them only if required by the client application to ensure logic/code correctness.
// That is, `transaction_items` are not a substitute for batch-write of multiple unrelated items.
// When a write of multiple unrelated items is desired, it is recommended to use separate
// `PutObjectRequest`s.
//
// Consistency guarantee:
// All `PutObjectRequest`s are strongly consistent i.e. they provide read-after-write and
// read-after-update consistency guarantees.
repeated KeyValue transaction_items = 3;
// Items to be deleted as a result of this `PutObjectRequest`.
//
// Each item in the `delete_items` field consists of a `key` and its corresponding `version`.
//
// Key-Level Versioning (Conditional Delete):
// The `version` is used to perform a version check before deleting the item.
// The delete will only succeed if the current database version against the `key` is the same as
// the `version` specified in the request.
//
// Skipping key-level versioning (Non-conditional Delete):
// If you wish to skip key-level version checks, set the `version` against the `key` to '-1'.
// This will perform a non-conditional delete query.
//
// Fails with `CONFLICT_EXCEPTION` as the ErrorCode if:
// * The requested item does not exist.
// * The requested item does exist but there is a version-number mismatch (in conditional delete)
// with the one in the database.
//
// Multiple items in the `delete_items` field, along with the `transaction_items`, are written in a
// database transaction in an all-or-nothing fashion.
//
// All items within a single `PutObjectRequest` must have distinct keys.
repeated KeyValue delete_items = 4;
}
// Server response for `PutObject` API.
message PutObjectResponse {
}
// Request payload to be used for `DeleteObject` API call to server.
message DeleteObjectRequest {
// `store_id` is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single `store_id`.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the `store_id` level.
string store_id = 1;
// Item to be deleted as a result of this `DeleteObjectRequest`.
//
// An item consists of a `key` and its corresponding `version`.
//
// Key-level Versioning (Conditional Delete):
// The item is only deleted if the current database version against the `key` is the same as
// the `version` specified in the request.
//
// Skipping key-level versioning (Non-conditional Delete):
// If you wish to skip key-level version checks, set the `version` against the `key` to '-1'.
// This will perform a non-conditional delete query.
//
// This operation is idempotent, that is, multiple delete calls for the same item will not fail.
//
// If the requested item does not exist, this operation will not fail.
// If you wish to perform stricter checks while deleting an item, consider using `PutObject` API.
KeyValue key_value = 2;
}
// Server response for `DeleteObject` API.
message DeleteObjectResponse{
}
// Request payload to be used for `ListKeyVersions` API call to server.
message ListKeyVersionsRequest {
// `store_id` is a keyspace identifier.
// Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
// All APIs operate within a single `store_id`.
// It is up to clients to use single or multiple stores for their use-case.
// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
// Authorization and billing can also be performed at the `store_id` level.
string store_id = 1;
// A `key_prefix` is a string of characters at the beginning of the key. Prefixes can be used as
// a way to organize key-values in a similar way to directories.
//
// If `key_prefix` is specified, the response results will be limited to those keys that begin with
// the specified prefix.
//
// If no `key_prefix` is specified or it is empty (""), all the keys are eligible to be returned in
// the response.
optional string key_prefix = 2;
// `page_size` is used by clients to specify the maximum number of results that can be returned by
// the server.
// The server may further constrain the maximum number of results returned in a single page.
// If the `page_size` is 0 or not set, the server will decide the number of results to be returned.
optional int32 page_size = 3;
// `page_token` is a pagination token.
//
// To query for the first page of `ListKeyVersions`, `page_token` must not be specified.
//
// For subsequent pages, use the value that was returned as `next_page_token` in the previous
// page's `ListKeyVersionsResponse`.
optional string page_token = 4;
}
// Server response for `ListKeyVersions` API.
message ListKeyVersionsResponse {
// Fetched keys and versions.
// Even though this API reuses the `KeyValue` struct, the `value` sub-field will not be set by the server.
repeated KeyValue key_versions = 1;
// `next_page_token` is a pagination token, used to retrieve the next page of results.
// Use this value to query for next-page of paginated `ListKeyVersions` operation, by specifying
// this value as the `page_token` in the next request.
//
// If `next_page_token` is empty (""), then the "last page" of results has been processed and
// there is no more data to be retrieved.
//
// If `next_page_token` is not empty, it does not necessarily mean that there is more data in the
// result set. The only way to know when you have reached the end of the result set is when
// `next_page_token` is empty.
//
// Caution: Clients must not assume a specific number of key_versions to be present in a page for
// paginated response.
optional string next_page_token = 2;
// `global_version` is a sequence-number/version of the whole store.
//
// `global_version` is only returned in response for the first page of the `ListKeyVersionsResponse`
// and is guaranteed to be read before reading any key-versions.
//
// In case of refreshing the complete key-version view on the client-side, correct usage for
// the returned `global_version` is as following:
// 1. Read `global_version` from the first page of paginated response and save it as local variable.
// 2. Update all the `key_versions` on client-side from all the pages of paginated response.
// 3. Update `global_version` on client_side from the local variable saved in step-1.
// This ensures that on client-side, all current `key_versions` were stored at `global_version` or later.
// This guarantee is helpful for ensuring the versioning correctness if using the `global_version`
// in `PutObject` API and can help avoid the race conditions related to it.
optional int64 global_version = 3;
}
// When HttpStatusCode is not ok (200), the response `content` contains a serialized `ErrorResponse`
// with the relevant `ErrorCode` and `message`
message ErrorResponse {
// The error code uniquely identifying an error condition.
// It is meant to be read and understood programmatically by code that detects/handles errors by
// type.
ErrorCode error_code = 1;
// The error message containing a generic description of the error condition in English.
// It is intended for a human audience only and should not be parsed to extract any information
// programmatically. Client-side code may use it for logging only.
string message = 2;
}
// ErrorCodes to be used in `ErrorResponse`
enum ErrorCode {
// Default protobuf Enum value. Will not be used as `ErrorCode` by server.
UNKNOWN = 0;
// Used when the request contains mismatched version (either key or global)
// in `PutObjectRequest`. For more info refer `PutObjectRequest`.
CONFLICT_EXCEPTION = 1;
// Used in the following cases:
// - The request was missing a required argument.
// - The specified argument was invalid, incomplete or in the wrong format.
// - The request body of api cannot be deserialized into corresponding protobuf object.
INVALID_REQUEST_EXCEPTION = 2;
// Used when an internal server error occurred, client is probably at no fault and can safely retry
// this error with exponential backoff.
INTERNAL_SERVER_EXCEPTION = 3;
// Used when the specified `key` in a `GetObjectRequest` does not exist.
NO_SUCH_KEY_EXCEPTION = 4;
// Used when authentication fails or in case of an unauthorized request.
AUTH_EXCEPTION = 5;
}
// Represents a key-value pair to be stored or retrieved.
message KeyValue {
// Key against which the value is stored.
string key = 1;
// Version field is used for key-level versioning.
// For first write of key, `version` should be '0'. If the write succeeds, clients must increment
// their corresponding key version (client-side) by 1.
// The server increments key version (server-side) for every successful write, hence this
// client-side increment is required to ensure matching versions. These updated key versions should
// be used in subsequent `PutObjectRequest`s for the keys.
int64 version = 2;
// Object value in bytes which is stored (in put) and fetched (in get).
// Clients must encrypt the secret contents of this blob client-side before sending it over the
// wire to the server in order to preserve privacy and security.
// Clients may use a `Storable` object, serialize it and set it here.
bytes value = 3;
}
// Represents a storable object that can be serialized and stored as `value` in `PutObjectRequest`.
// Only provided as a helper object for ease of use by clients.
// Clients MUST encrypt the `PlaintextBlob` before using it as `data` in `Storable`.
// The server does not use or read anything from `Storable`, Clients may use its fields as
// required.
message Storable {
// Represents an encrypted and serialized `PlaintextBlob`. MUST encrypt the whole `PlaintextBlob`
// using client-side encryption before setting here.
bytes data = 1;
// Represents encryption related metadata
EncryptionMetadata encryption_metadata = 2;
}
// Represents encryption related metadata
message EncryptionMetadata {
// The encryption algorithm used for encrypting the `PlaintextBlob`.
string cipher_format = 1;
// The nonce used for encryption. Nonce is a random or unique value used to ensure that the same
// plaintext results in different ciphertexts every time it is encrypted.
bytes nonce = 2;
// The authentication tag used for encryption. It provides integrity and authenticity assurance
// for the encrypted data.
bytes tag = 3;
}
// Represents a data blob, which is encrypted, serialized and later used in `Storable.data`.
// Since the whole `Storable.data` is client-side encrypted, the server cannot understand this.
message PlaintextBlob {
// The unencrypted value.
bytes value = 1;
// The version of the value. Can be used by client to verify version integrity.
int64 version = 2;
}