ruby-libstorj 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +111 -0
  7. data/Guardfile +21 -0
  8. data/LICENSE +502 -0
  9. data/README.md +262 -0
  10. data/Rakefile +76 -0
  11. data/ext/libstorj/.gitignore +47 -0
  12. data/ext/libstorj/.travis.yml +27 -0
  13. data/ext/libstorj/Doxyfile +2427 -0
  14. data/ext/libstorj/LICENSE +502 -0
  15. data/ext/libstorj/Makefile.am +6 -0
  16. data/ext/libstorj/README.md +198 -0
  17. data/ext/libstorj/autogen.sh +3 -0
  18. data/ext/libstorj/configure.ac +64 -0
  19. data/ext/libstorj/depends/Makefile +153 -0
  20. data/ext/libstorj/depends/config.guess +1462 -0
  21. data/ext/libstorj/depends/config.sub +1823 -0
  22. data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
  23. data/ext/libstorj/depends/packages/cctools.mk +7 -0
  24. data/ext/libstorj/depends/packages/clang.mk +7 -0
  25. data/ext/libstorj/depends/packages/gmp.mk +23 -0
  26. data/ext/libstorj/depends/packages/gnutls.mk +25 -0
  27. data/ext/libstorj/depends/packages/json-c.mk +7 -0
  28. data/ext/libstorj/depends/packages/libcurl.mk +39 -0
  29. data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
  30. data/ext/libstorj/depends/packages/libuv.mk +7 -0
  31. data/ext/libstorj/depends/packages/nettle.mk +30 -0
  32. data/ext/libstorj/libstorj.pc.in +11 -0
  33. data/ext/libstorj/src/Makefile.am +23 -0
  34. data/ext/libstorj/src/bip39.c +233 -0
  35. data/ext/libstorj/src/bip39.h +64 -0
  36. data/ext/libstorj/src/bip39_english.h +2074 -0
  37. data/ext/libstorj/src/cli.c +1494 -0
  38. data/ext/libstorj/src/crypto.c +525 -0
  39. data/ext/libstorj/src/crypto.h +178 -0
  40. data/ext/libstorj/src/downloader.c +1923 -0
  41. data/ext/libstorj/src/downloader.h +163 -0
  42. data/ext/libstorj/src/http.c +688 -0
  43. data/ext/libstorj/src/http.h +175 -0
  44. data/ext/libstorj/src/rs.c +962 -0
  45. data/ext/libstorj/src/rs.h +99 -0
  46. data/ext/libstorj/src/storj.c +1523 -0
  47. data/ext/libstorj/src/storj.h +1014 -0
  48. data/ext/libstorj/src/uploader.c +2736 -0
  49. data/ext/libstorj/src/uploader.h +181 -0
  50. data/ext/libstorj/src/utils.c +336 -0
  51. data/ext/libstorj/src/utils.h +65 -0
  52. data/ext/libstorj/test/Makefile.am +27 -0
  53. data/ext/libstorj/test/mockbridge.c +260 -0
  54. data/ext/libstorj/test/mockbridge.json +687 -0
  55. data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
  56. data/ext/libstorj/test/mockfarmer.c +358 -0
  57. data/ext/libstorj/test/storjtests.h +41 -0
  58. data/ext/libstorj/test/tests.c +1617 -0
  59. data/ext/libstorj/test/tests_rs.c +869 -0
  60. data/ext/ruby-libstorj/extconf.rb +8 -0
  61. data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
  62. data/lib/ruby-libstorj.rb +1 -0
  63. data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
  64. data/lib/ruby-libstorj/env.rb +178 -0
  65. data/lib/ruby-libstorj/ext/bucket.rb +71 -0
  66. data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
  67. data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
  68. data/lib/ruby-libstorj/ext/ext.rb +71 -0
  69. data/lib/ruby-libstorj/ext/file.rb +84 -0
  70. data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
  71. data/lib/ruby-libstorj/ext/json_request.rb +51 -0
  72. data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
  73. data/lib/ruby-libstorj/ext/types.rb +226 -0
  74. data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
  75. data/lib/ruby-libstorj/libstorj.rb +22 -0
  76. data/lib/ruby-libstorj/mixins/storj.rb +27 -0
  77. data/lib/ruby-libstorj/struct.rb +42 -0
  78. data/ruby-libstorj.gemspec +57 -0
  79. data/spec/helpers/options.yml.example +22 -0
  80. data/spec/helpers/shared_rake_examples.rb +132 -0
  81. data/spec/helpers/storj_options.rb +96 -0
  82. data/spec/helpers/upload.data +3 -0
  83. data/spec/helpers/upload.data.sha256 +1 -0
  84. data/spec/libstorj_spec.rb +0 -0
  85. data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
  86. data/spec/ruby-libstorj/env_spec.rb +353 -0
  87. data/spec/ruby-libstorj/ext_spec.rb +75 -0
  88. data/spec/ruby-libstorj/json_request_spec.rb +13 -0
  89. data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
  90. data/spec/ruby-libstorj/struct_spec.rb +64 -0
  91. data/spec/spec_helper.rb +113 -0
  92. metadata +136 -0
@@ -0,0 +1,99 @@
1
+ #ifndef __RS_H_
2
+ #define __RS_H_
3
+
4
+ /* use small value to save memory */
5
+ #ifndef DATA_SHARDS_MAX
6
+ #define DATA_SHARDS_MAX (255)
7
+ #endif
8
+
9
+ /* use other memory allocator */
10
+ #ifndef RS_MALLOC
11
+ #define RS_MALLOC(x) malloc(x)
12
+ #endif
13
+
14
+ #ifndef RS_FREE
15
+ #define RS_FREE(x) free(x)
16
+ #endif
17
+
18
+ #ifndef RS_CALLOC
19
+ #define RS_CALLOC(n, x) calloc(n, x)
20
+ #endif
21
+
22
+ typedef struct _reed_solomon {
23
+ int data_shards;
24
+ int parity_shards;
25
+ int shards;
26
+ uint8_t* m;
27
+ uint8_t* parity;
28
+ } reed_solomon;
29
+
30
+ /**
31
+ * @brief Initializes data structures used for computations in GF.
32
+ */
33
+ void fec_init(void);
34
+
35
+ /**
36
+ * @brief Will initialize new reed solomon
37
+ *
38
+ * @param[in] data_shards Total number of data shards
39
+ * @param[in] parity_shards The total number of parity shards
40
+ * @return A null value on error
41
+ */
42
+ reed_solomon* reed_solomon_new(int data_shards, int parity_shards);
43
+
44
+ /**
45
+ * @brief Will free existing reed solomon
46
+ *
47
+ * @param[in] rs
48
+ */
49
+ void reed_solomon_release(reed_solomon* rs);
50
+
51
+ int reed_solomon_encode(reed_solomon* rs,
52
+ uint8_t** data_blocks,
53
+ uint8_t** fec_blocks,
54
+ uint64_t block_size,
55
+ uint64_t total_bytes);
56
+
57
+
58
+ int reed_solomon_decode(reed_solomon* rs,
59
+ uint8_t **data_blocks,
60
+ uint64_t block_size,
61
+ uint8_t **dec_fec_blocks,
62
+ unsigned int *fec_block_nos,
63
+ unsigned int *erased_blocks,
64
+ int nr_fec_blocks,
65
+ uint64_t total_bytes);
66
+
67
+
68
+ /**
69
+ * @brief Will encode large buffer into parity shards
70
+ *
71
+ * @param[in] rs
72
+ * @param[in] data_blocks Data shards
73
+ * @param[in] fec_blocks Parity shards
74
+ * @param[in] nr_shards Total number of shards/blocks
75
+ * @param[in] block_size The size of each shard
76
+ * @param[in] total_bytes The total size used for zero padding the last shard
77
+ * @return A non-zero error value on failure and 0 on success.
78
+ */
79
+ int reed_solomon_encode2(reed_solomon* rs, uint8_t** data_blocks,
80
+ uint8_t** fec_blocks, int nr_shards, uint64_t block_size,
81
+ uint64_t total_bytes);
82
+
83
+ /**
84
+ * @brief Will repair missing data in blocks
85
+ *
86
+ * @param[in] rs
87
+ * @param[in] data_blocks Data shards
88
+ * @param[in] fec_blocks Parity shards
89
+ * @param[in] marks An array with 1 used to mark missing blocks
90
+ * @param[in] nr_shards Total number of shards/blocks
91
+ * @param[in] block_size The size of each shard
92
+ * @param[in] total_bytes The total size used for zero padding the last shard
93
+ * @return A non-zero error value on failure and 0 on success.
94
+ */
95
+ int reed_solomon_reconstruct(reed_solomon* rs, uint8_t** data_blocks,
96
+ uint8_t** fec_blocks, uint8_t* marks,
97
+ int nr_shards, uint64_t block_size,
98
+ uint64_t total_bytes);
99
+ #endif
@@ -0,0 +1,1523 @@
1
+ #include "storj.h"
2
+ #include "http.h"
3
+ #include "utils.h"
4
+ #include "crypto.h"
5
+
6
+ static inline void noop() {};
7
+
8
+ static void json_request_worker(uv_work_t *work)
9
+ {
10
+ json_request_t *req = work->data;
11
+ int status_code = 0;
12
+
13
+ req->error_code = fetch_json(req->http_options,
14
+ req->options, req->method, req->path, req->body,
15
+ req->auth, &req->response, &status_code);
16
+
17
+ req->status_code = status_code;
18
+ }
19
+
20
+ static void create_bucket_request_worker(uv_work_t *work)
21
+ {
22
+ create_bucket_request_t *req = work->data;
23
+ int status_code = 0;
24
+
25
+ // Derive a key based on the master seed and bucket name magic number
26
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
27
+ generate_bucket_key(req->encrypt_options->mnemonic,
28
+ BUCKET_NAME_MAGIC,
29
+ &bucket_key_as_str);
30
+
31
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
32
+ if (!bucket_key) {
33
+ req->error_code = STORJ_MEMORY_ERROR;
34
+ return;
35
+ }
36
+
37
+ free(bucket_key_as_str);
38
+
39
+ // Get bucket name encryption key with first half of hmac w/ magic
40
+ struct hmac_sha512_ctx ctx1;
41
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
42
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
43
+ uint8_t key[SHA256_DIGEST_SIZE];
44
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
45
+
46
+ // Generate the synthetic iv with first half of hmac w/ name
47
+ struct hmac_sha512_ctx ctx2;
48
+ hmac_sha512_set_key(&ctx2, SHA256_DIGEST_SIZE, bucket_key);
49
+ hmac_sha512_update(&ctx2, strlen(req->bucket_name),
50
+ (uint8_t *)req->bucket_name);
51
+ uint8_t bucketname_iv[SHA256_DIGEST_SIZE];
52
+ hmac_sha512_digest(&ctx2, SHA256_DIGEST_SIZE, bucketname_iv);
53
+
54
+ free(bucket_key);
55
+
56
+ // Encrypt the bucket name
57
+ char *encrypted_bucket_name;
58
+ encrypt_meta(req->bucket_name, key, bucketname_iv, &encrypted_bucket_name);
59
+ req->encrypted_bucket_name = encrypted_bucket_name;
60
+
61
+ struct json_object *body = json_object_new_object();
62
+ json_object *name = json_object_new_string(req->encrypted_bucket_name);
63
+ json_object_object_add(body, "name", name);
64
+
65
+ req->error_code = fetch_json(req->http_options,
66
+ req->bridge_options, "POST", "/buckets", body,
67
+ true, &req->response, &status_code);
68
+
69
+ json_object_put(body);
70
+
71
+ if (req->response != NULL) {
72
+ req->bucket = malloc(sizeof(storj_bucket_meta_t));
73
+
74
+ struct json_object *id;
75
+ json_object_object_get_ex(req->response, "id", &id);
76
+
77
+ req->bucket->id = json_object_get_string(id);
78
+ req->bucket->name = req->bucket_name;
79
+ req->bucket->decrypted = true;
80
+ }
81
+
82
+ req->status_code = status_code;
83
+ }
84
+
85
+ static void get_buckets_request_worker(uv_work_t *work)
86
+ {
87
+ get_buckets_request_t *req = work->data;
88
+ int status_code = 0;
89
+
90
+ req->error_code = fetch_json(req->http_options,
91
+ req->options, req->method, req->path, req->body,
92
+ req->auth, &req->response, &status_code);
93
+
94
+ req->status_code = status_code;
95
+
96
+ int num_buckets = 0;
97
+ if (req->response != NULL &&
98
+ json_object_is_type(req->response, json_type_array)) {
99
+ num_buckets = json_object_array_length(req->response);
100
+ }
101
+
102
+ if (num_buckets > 0) {
103
+ req->buckets = malloc(sizeof(storj_bucket_meta_t) * num_buckets);
104
+ req->total_buckets = num_buckets;
105
+ }
106
+
107
+ // Derive a key based on the master seed
108
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
109
+ generate_bucket_key(req->encrypt_options->mnemonic,
110
+ BUCKET_NAME_MAGIC,
111
+ &bucket_key_as_str);
112
+
113
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
114
+ if (!bucket_key) {
115
+ req->error_code = STORJ_MEMORY_ERROR;
116
+ return;
117
+ }
118
+
119
+ free(bucket_key_as_str);
120
+
121
+ // Get bucket name encryption key with first half of hmac w/ magic
122
+ struct hmac_sha512_ctx ctx1;
123
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
124
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
125
+ uint8_t key[SHA256_DIGEST_SIZE];
126
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
127
+
128
+ free(bucket_key);
129
+
130
+ struct json_object *bucket_item;
131
+ struct json_object *name;
132
+ struct json_object *created;
133
+ struct json_object *id;
134
+
135
+ for (int i = 0; i < num_buckets; i++) {
136
+ bucket_item = json_object_array_get_idx(req->response, i);
137
+
138
+ json_object_object_get_ex(bucket_item, "id", &id);
139
+ json_object_object_get_ex(bucket_item, "name", &name);
140
+ json_object_object_get_ex(bucket_item, "created", &created);
141
+
142
+ storj_bucket_meta_t *bucket = &req->buckets[i];
143
+ bucket->id = json_object_get_string(id);
144
+ bucket->decrypted = false;
145
+ bucket->created = json_object_get_string(created);
146
+ bucket->name = NULL;
147
+
148
+ // Attempt to decrypt the name, otherwise
149
+ // we will default the name to the encrypted text.
150
+ // The decrypted flag will be set to indicate the status
151
+ // of decryption for alternative display.
152
+ const char *encrypted_name = json_object_get_string(name);
153
+ if (!encrypted_name) {
154
+ continue;
155
+ }
156
+ char *decrypted_name;
157
+ int error_status = decrypt_meta(encrypted_name, key,
158
+ &decrypted_name);
159
+ if (!error_status) {
160
+ bucket->decrypted = true;
161
+ bucket->name = decrypted_name;
162
+ } else {
163
+ bucket->decrypted = false;
164
+ bucket->name = strdup(encrypted_name);
165
+ }
166
+ }
167
+ }
168
+
169
+ static void get_bucket_request_worker(uv_work_t *work)
170
+ {
171
+ get_bucket_request_t *req = work->data;
172
+ int status_code = 0;
173
+
174
+ req->error_code = fetch_json(req->http_options,
175
+ req->options, req->method, req->path, req->body,
176
+ req->auth, &req->response, &status_code);
177
+
178
+ req->status_code = status_code;
179
+
180
+ if (!req->response) {
181
+ req->bucket = NULL;
182
+ return;
183
+ }
184
+
185
+ // Derive a key based on the master seed
186
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
187
+ generate_bucket_key(req->encrypt_options->mnemonic,
188
+ BUCKET_NAME_MAGIC,
189
+ &bucket_key_as_str);
190
+
191
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
192
+ if (!bucket_key) {
193
+ req->error_code = STORJ_MEMORY_ERROR;
194
+ return;
195
+ }
196
+
197
+ free(bucket_key_as_str);
198
+
199
+ // Get bucket name encryption key with first half of hmac w/ magic
200
+ struct hmac_sha512_ctx ctx1;
201
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
202
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
203
+ uint8_t key[SHA256_DIGEST_SIZE];
204
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
205
+
206
+ free(bucket_key);
207
+
208
+ struct json_object *name;
209
+ struct json_object *created;
210
+ struct json_object *id;
211
+
212
+ json_object_object_get_ex(req->response, "id", &id);
213
+ json_object_object_get_ex(req->response, "name", &name);
214
+ json_object_object_get_ex(req->response, "created", &created);
215
+
216
+ req->bucket = malloc(sizeof(storj_bucket_meta_t));
217
+ req->bucket->id = json_object_get_string(id);
218
+ req->bucket->decrypted = false;
219
+ req->bucket->created = json_object_get_string(created);
220
+ req->bucket->name = NULL;
221
+
222
+ // Attempt to decrypt the name, otherwise
223
+ // we will default the name to the encrypted text.
224
+ // The decrypted flag will be set to indicate the status
225
+ // of decryption for alternative display.
226
+ const char *encrypted_name = json_object_get_string(name);
227
+ if (encrypted_name) {
228
+ char *decrypted_name;
229
+ int error_status = decrypt_meta(encrypted_name, key,
230
+ &decrypted_name);
231
+ if (!error_status) {
232
+ req->bucket->decrypted = true;
233
+ req->bucket->name = decrypted_name;
234
+ } else {
235
+ req->bucket->decrypted = false;
236
+ req->bucket->name = strdup(encrypted_name);
237
+ }
238
+ }
239
+ }
240
+
241
+ static void list_files_request_worker(uv_work_t *work)
242
+ {
243
+ list_files_request_t *req = work->data;
244
+ int status_code = 0;
245
+
246
+ req->error_code = fetch_json(req->http_options,
247
+ req->options, req->method, req->path, req->body,
248
+ req->auth, &req->response, &status_code);
249
+
250
+ req->status_code = status_code;
251
+
252
+ int num_files = 0;
253
+ if (req->response != NULL &&
254
+ json_object_is_type(req->response, json_type_array)) {
255
+ num_files = json_object_array_length(req->response);
256
+ }
257
+
258
+ if (num_files > 0) {
259
+ req->files = malloc(sizeof(storj_file_meta_t) * num_files);
260
+ req->total_files = num_files;
261
+ }
262
+
263
+ // Get the bucket key to encrypt the filename from bucket id
264
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
265
+ generate_bucket_key(req->encrypt_options->mnemonic,
266
+ req->bucket_id,
267
+ &bucket_key_as_str);
268
+
269
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
270
+ if (!bucket_key) {
271
+ req->error_code = STORJ_MEMORY_ERROR;
272
+ return;
273
+ }
274
+
275
+ free(bucket_key_as_str);
276
+
277
+ // Get file name encryption key with first half of hmac w/ magic
278
+ struct hmac_sha512_ctx ctx1;
279
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
280
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
281
+ uint8_t key[SHA256_DIGEST_SIZE];
282
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
283
+
284
+ free(bucket_key);
285
+
286
+ struct json_object *file;
287
+ struct json_object *filename;
288
+ struct json_object *mimetype;
289
+ struct json_object *size;
290
+ struct json_object *id;
291
+ struct json_object *created;
292
+
293
+ for (int i = 0; i < num_files; i++) {
294
+ file = json_object_array_get_idx(req->response, i);
295
+
296
+ json_object_object_get_ex(file, "filename", &filename);
297
+ json_object_object_get_ex(file, "mimetype", &mimetype);
298
+ json_object_object_get_ex(file, "size", &size);
299
+ json_object_object_get_ex(file, "id", &id);
300
+ json_object_object_get_ex(file, "created", &created);
301
+
302
+ storj_file_meta_t *file = &req->files[i];
303
+
304
+ file->created = json_object_get_string(created);
305
+ file->mimetype = json_object_get_string(mimetype);
306
+ file->size = json_object_get_int64(size);
307
+ file->erasure = NULL;
308
+ file->index = NULL;
309
+ file->hmac = NULL; // TODO though this value is not needed here
310
+ file->id = json_object_get_string(id);
311
+ file->decrypted = false;
312
+ file->filename = NULL;
313
+
314
+ // Attempt to decrypt the filename, otherwise
315
+ // we will default the filename to the encrypted text.
316
+ // The decrypted flag will be set to indicate the status
317
+ // of decryption for alternative display.
318
+ const char *encrypted_file_name = json_object_get_string(filename);
319
+ if (!encrypted_file_name) {
320
+ continue;
321
+ }
322
+ char *decrypted_file_name;
323
+ int error_status = decrypt_meta(encrypted_file_name, key,
324
+ &decrypted_file_name);
325
+ if (!error_status) {
326
+ file->decrypted = true;
327
+ file->filename = decrypted_file_name;
328
+ } else {
329
+ file->decrypted = false;
330
+ file->filename = strdup(encrypted_file_name);
331
+ }
332
+ }
333
+ }
334
+
335
+ static uv_work_t *uv_work_new()
336
+ {
337
+ uv_work_t *work = malloc(sizeof(uv_work_t));
338
+ return work;
339
+ }
340
+
341
+ static json_request_t *json_request_new(
342
+ storj_http_options_t *http_options,
343
+ storj_bridge_options_t *options,
344
+ char *method,
345
+ char *path,
346
+ struct json_object *request_body,
347
+ bool auth,
348
+ void *handle)
349
+ {
350
+
351
+ json_request_t *req = malloc(sizeof(json_request_t));
352
+ if (!req) {
353
+ return NULL;
354
+ }
355
+
356
+ req->http_options = http_options;
357
+ req->options = options;
358
+ req->method = method;
359
+ req->path = path;
360
+ req->auth = auth;
361
+ req->body = request_body;
362
+ req->response = NULL;
363
+ req->error_code = 0;
364
+ req->status_code = 0;
365
+ req->handle = handle;
366
+
367
+ return req;
368
+ }
369
+
370
+ static list_files_request_t *list_files_request_new(
371
+ storj_http_options_t *http_options,
372
+ storj_bridge_options_t *options,
373
+ storj_encrypt_options_t *encrypt_options,
374
+ const char *bucket_id,
375
+ char *method,
376
+ char *path,
377
+ struct json_object *request_body,
378
+ bool auth,
379
+ void *handle)
380
+ {
381
+ list_files_request_t *req = malloc(sizeof(list_files_request_t));
382
+ if (!req) {
383
+ return NULL;
384
+ }
385
+
386
+ req->http_options = http_options;
387
+ req->options = options;
388
+ req->encrypt_options = encrypt_options;
389
+ req->bucket_id = bucket_id;
390
+ req->method = method;
391
+ req->path = path;
392
+ req->auth = auth;
393
+ req->body = request_body;
394
+ req->response = NULL;
395
+ req->files = NULL;
396
+ req->total_files = 0;
397
+ req->error_code = 0;
398
+ req->status_code = 0;
399
+ req->handle = handle;
400
+
401
+ return req;
402
+ }
403
+
404
+ static create_bucket_request_t *create_bucket_request_new(
405
+ storj_http_options_t *http_options,
406
+ storj_bridge_options_t *bridge_options,
407
+ storj_encrypt_options_t *encrypt_options,
408
+ const char *bucket_name,
409
+ void *handle)
410
+ {
411
+ create_bucket_request_t *req = malloc(sizeof(create_bucket_request_t));
412
+ if (!req) {
413
+ return NULL;
414
+ }
415
+
416
+ req->http_options = http_options;
417
+ req->encrypt_options = encrypt_options;
418
+ req->bridge_options = bridge_options;
419
+ req->bucket_name = bucket_name;
420
+ req->encrypted_bucket_name = NULL;
421
+ req->response = NULL;
422
+ req->bucket = NULL;
423
+ req->error_code = 0;
424
+ req->status_code = 0;
425
+ req->handle = handle;
426
+
427
+ return req;
428
+ }
429
+
430
+ static get_buckets_request_t *get_buckets_request_new(
431
+ storj_http_options_t *http_options,
432
+ storj_bridge_options_t *options,
433
+ storj_encrypt_options_t *encrypt_options,
434
+ char *method,
435
+ char *path,
436
+ struct json_object *request_body,
437
+ bool auth,
438
+ void *handle)
439
+ {
440
+ get_buckets_request_t *req = malloc(sizeof(get_buckets_request_t));
441
+ if (!req) {
442
+ return NULL;
443
+ }
444
+
445
+ req->http_options = http_options;
446
+ req->options = options;
447
+ req->encrypt_options = encrypt_options;
448
+ req->method = method;
449
+ req->path = path;
450
+ req->auth = auth;
451
+ req->body = request_body;
452
+ req->response = NULL;
453
+ req->buckets = NULL;
454
+ req->total_buckets = 0;
455
+ req->error_code = 0;
456
+ req->status_code = 0;
457
+ req->handle = handle;
458
+
459
+ return req;
460
+ }
461
+
462
+ static get_bucket_request_t *get_bucket_request_new(
463
+ storj_http_options_t *http_options,
464
+ storj_bridge_options_t *options,
465
+ storj_encrypt_options_t *encrypt_options,
466
+ char *method,
467
+ char *path,
468
+ struct json_object *request_body,
469
+ bool auth,
470
+ void *handle)
471
+ {
472
+ get_bucket_request_t *req = malloc(sizeof(get_bucket_request_t));
473
+ if (!req) {
474
+ return NULL;
475
+ }
476
+
477
+ req->http_options = http_options;
478
+ req->options = options;
479
+ req->encrypt_options = encrypt_options;
480
+ req->method = method;
481
+ req->path = path;
482
+ req->auth = auth;
483
+ req->body = request_body;
484
+ req->response = NULL;
485
+ req->bucket = NULL;
486
+ req->error_code = 0;
487
+ req->status_code = 0;
488
+ req->handle = handle;
489
+
490
+ return req;
491
+ }
492
+
493
+ static uv_work_t *json_request_work_new(
494
+ storj_env_t *env,
495
+ char *method,
496
+ char *path,
497
+ struct json_object *request_body,
498
+ bool auth,
499
+ void *handle)
500
+ {
501
+ uv_work_t *work = uv_work_new();
502
+ if (!work) {
503
+ return NULL;
504
+ }
505
+ work->data = json_request_new(env->http_options,
506
+ env->bridge_options, method, path,
507
+ request_body, auth, handle);
508
+
509
+ if (!work->data) {
510
+ return NULL;
511
+ }
512
+
513
+ return work;
514
+ }
515
+
516
+ static void default_logger(const char *message,
517
+ int level,
518
+ void *handle)
519
+ {
520
+ puts(message);
521
+ }
522
+
523
+ static void log_formatter(storj_log_options_t *options,
524
+ void *handle,
525
+ int level,
526
+ const char *format,
527
+ va_list args)
528
+ {
529
+ va_list args_cpy;
530
+ va_copy(args_cpy, args);
531
+ int length = vsnprintf(0, 0, format, args_cpy);
532
+ va_end(args_cpy);
533
+
534
+ if (length > 0) {
535
+ char message[length + 1];
536
+ if (vsnprintf(message, length + 1, format, args)) {
537
+ options->logger(message, level, handle);
538
+ }
539
+ }
540
+ }
541
+
542
+ static void log_formatter_debug(storj_log_options_t *options, void *handle,
543
+ const char *format, ...)
544
+ {
545
+ va_list args;
546
+ va_start(args, format);
547
+ log_formatter(options, handle, 4, format, args);
548
+ va_end(args);
549
+ }
550
+
551
+ static void log_formatter_info(storj_log_options_t *options, void *handle,
552
+ const char *format, ...)
553
+ {
554
+ va_list args;
555
+ va_start(args, format);
556
+ log_formatter(options, handle, 3, format, args);
557
+ va_end(args);
558
+ }
559
+
560
+ static void log_formatter_warn(storj_log_options_t *options, void *handle,
561
+ const char *format, ...)
562
+ {
563
+ va_list args;
564
+ va_start(args, format);
565
+ log_formatter(options, handle, 2, format, args);
566
+ va_end(args);
567
+ }
568
+
569
+ static void log_formatter_error(storj_log_options_t *options, void *handle,
570
+ const char *format, ...)
571
+ {
572
+ va_list args;
573
+ va_start(args, format);
574
+ log_formatter(options, handle, 1, format, args);
575
+ va_end(args);
576
+ }
577
+
578
+ STORJ_API struct storj_env *storj_init_env(storj_bridge_options_t *options,
579
+ storj_encrypt_options_t *encrypt_options,
580
+ storj_http_options_t *http_options,
581
+ storj_log_options_t *log_options)
582
+ {
583
+ curl_global_init(CURL_GLOBAL_ALL);
584
+
585
+ uv_loop_t *loop = uv_default_loop();
586
+ if (!loop) {
587
+ return NULL;
588
+ }
589
+
590
+ storj_env_t *env = malloc(sizeof(storj_env_t));
591
+ if (!env) {
592
+ return NULL;
593
+ }
594
+
595
+ // setup the uv event loop
596
+ env->loop = loop;
597
+
598
+ // deep copy bridge options
599
+ storj_bridge_options_t *bo = malloc(sizeof(storj_bridge_options_t));
600
+ if (!bo) {
601
+ return NULL;
602
+ }
603
+
604
+ bo->proto = strdup(options->proto);
605
+ bo->host = strdup(options->host);
606
+ bo->port = options->port;
607
+ if (options->user) {
608
+ bo->user = strdup(options->user);
609
+ } else {
610
+ bo->user = NULL;
611
+ }
612
+
613
+ #ifdef _POSIX_MEMLOCK
614
+ int page_size = sysconf(_SC_PAGESIZE);
615
+ #elif _WIN32
616
+ SYSTEM_INFO si;
617
+ GetSystemInfo (&si);
618
+ uintptr_t page_size = si.dwPageSize;
619
+ #endif
620
+
621
+ if (options->pass) {
622
+ // prevent bridge password from being swapped unencrypted to disk
623
+ #ifdef _POSIX_MEMLOCK
624
+ int pass_len = strlen(options->pass);
625
+ if (pass_len >= page_size) {
626
+ return NULL;
627
+ }
628
+
629
+ #ifdef HAVE_ALIGNED_ALLOC
630
+ bo->pass = aligned_alloc(page_size, page_size);
631
+ #elif HAVE_POSIX_MEMALIGN
632
+ bo->pass = NULL;
633
+ if (posix_memalign((void *)&bo->pass, page_size, page_size)) {
634
+ return NULL;
635
+ }
636
+ #else
637
+ bo->pass = malloc(page_size);
638
+ #endif
639
+
640
+ if (bo->pass == NULL) {
641
+ return NULL;
642
+ }
643
+ memset((char *)bo->pass, 0, page_size);
644
+ memcpy((char *)bo->pass, options->pass, pass_len);
645
+ if (mlock(bo->pass, pass_len)) {
646
+ return NULL;
647
+ }
648
+ #elif _WIN32
649
+ int pass_len = strlen(options->pass);
650
+ bo->pass = VirtualAlloc(NULL, page_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
651
+ if (bo->pass == NULL) {
652
+ return NULL;
653
+ }
654
+ memset((char *)bo->pass, 0, page_size);
655
+ memcpy((char *)bo->pass, options->pass, pass_len);
656
+ if (!VirtualLock((char *)bo->pass, pass_len)) {
657
+ return NULL;
658
+ }
659
+ #else
660
+ bo->pass = strdup(options->pass);
661
+ #endif
662
+ } else {
663
+ bo->pass = NULL;
664
+ }
665
+
666
+ env->bridge_options = bo;
667
+
668
+ // deep copy encryption options
669
+ storj_encrypt_options_t *eo = malloc(sizeof(storj_encrypt_options_t));
670
+ if (!eo) {
671
+ return NULL;
672
+ }
673
+
674
+ if (encrypt_options && encrypt_options->mnemonic) {
675
+
676
+ // prevent file encryption mnemonic from being swapped unencrypted to disk
677
+ #ifdef _POSIX_MEMLOCK
678
+ int mnemonic_len = strlen(encrypt_options->mnemonic);
679
+ if (mnemonic_len >= page_size) {
680
+ return NULL;
681
+ }
682
+
683
+ #ifdef HAVE_ALIGNED_ALLOC
684
+ eo->mnemonic = aligned_alloc(page_size, page_size);
685
+ #elif HAVE_POSIX_MEMALIGN
686
+ eo->mnemonic = NULL;
687
+ if (posix_memalign((void *)&eo->mnemonic, page_size, page_size)) {
688
+ return NULL;
689
+ }
690
+ #else
691
+ eo->mnemonic = malloc(page_size);
692
+ #endif
693
+
694
+ if (eo->mnemonic == NULL) {
695
+ return NULL;
696
+ }
697
+
698
+ memset((char *)eo->mnemonic, 0, page_size);
699
+ memcpy((char *)eo->mnemonic, encrypt_options->mnemonic, mnemonic_len);
700
+ if (mlock(eo->mnemonic, mnemonic_len)) {
701
+ return NULL;
702
+ }
703
+ #elif _WIN32
704
+ int mnemonic_len = strlen(encrypt_options->mnemonic);
705
+ eo->mnemonic = VirtualAlloc(NULL, page_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
706
+ if (eo->mnemonic == NULL) {
707
+ return NULL;
708
+ }
709
+ memset((char *)eo->mnemonic, 0, page_size);
710
+ memcpy((char *)eo->mnemonic, encrypt_options->mnemonic, mnemonic_len);
711
+ if (!VirtualLock((char *)eo->mnemonic, mnemonic_len)) {
712
+ return NULL;
713
+ }
714
+ #else
715
+ eo->mnemonic = strdup(encrypt_options->mnemonic);
716
+ #endif
717
+ } else {
718
+ eo->mnemonic = NULL;
719
+ }
720
+
721
+ env->encrypt_options = eo;
722
+
723
+ // Set tmp_path
724
+ struct stat sb;
725
+ env->tmp_path = NULL;
726
+ if (env->tmp_path &&
727
+ stat(env->tmp_path, &sb) == 0 &&
728
+ S_ISDIR(sb.st_mode)) {
729
+ env->tmp_path = strdup(env->tmp_path);
730
+ } else if (getenv("STORJ_TEMP") &&
731
+ stat(getenv("STORJ_TEMP"), &sb) == 0 &&
732
+ S_ISDIR(sb.st_mode)) {
733
+ env->tmp_path = strdup(getenv("STORJ_TEMP"));
734
+ #ifdef _WIN32
735
+ } else if (getenv("TEMP") &&
736
+ stat(getenv("TEMP"), &sb) == 0 &&
737
+ S_ISDIR(sb.st_mode)) {
738
+ env->tmp_path = strdup(getenv("TEMP"));
739
+ #else
740
+ } else if ("/tmp" && stat("/tmp", &sb) == 0 && S_ISDIR(sb.st_mode)) {
741
+ env->tmp_path = strdup("/tmp");
742
+ #endif
743
+ } else {
744
+ env->tmp_path = NULL;
745
+ }
746
+
747
+ // deep copy the http options
748
+ storj_http_options_t *ho = malloc(sizeof(storj_http_options_t));
749
+ if (!ho) {
750
+ return NULL;
751
+ }
752
+ ho->user_agent = strdup(http_options->user_agent);
753
+ if (http_options->proxy_url) {
754
+ ho->proxy_url = strdup(http_options->proxy_url);
755
+ } else {
756
+ ho->proxy_url = NULL;
757
+ }
758
+ if (http_options->cainfo_path) {
759
+ ho->cainfo_path = strdup(http_options->cainfo_path);
760
+ } else {
761
+ ho->cainfo_path = NULL;
762
+ }
763
+ ho->low_speed_limit = http_options->low_speed_limit;
764
+ ho->low_speed_time = http_options->low_speed_time;
765
+ if (http_options->timeout == 0 ||
766
+ http_options->timeout >= STORJ_HTTP_TIMEOUT) {
767
+ ho->timeout = http_options->timeout;
768
+ } else {
769
+ ho->timeout = STORJ_HTTP_TIMEOUT;
770
+ }
771
+
772
+ env->http_options = ho;
773
+
774
+ // setup the log options
775
+ env->log_options = log_options;
776
+ if (!env->log_options->logger) {
777
+ env->log_options->logger = default_logger;
778
+ }
779
+
780
+ storj_log_levels_t *log = malloc(sizeof(storj_log_levels_t));
781
+ if (!log) {
782
+ return NULL;
783
+ }
784
+
785
+ log->debug = (storj_logger_format_fn)noop;
786
+ log->info = (storj_logger_format_fn)noop;
787
+ log->warn = (storj_logger_format_fn)noop;
788
+ log->error = (storj_logger_format_fn)noop;
789
+
790
+ switch(log_options->level) {
791
+ case 4:
792
+ log->debug = log_formatter_debug;
793
+ case 3:
794
+ log->info = log_formatter_info;
795
+ case 2:
796
+ log->warn = log_formatter_warn;
797
+ case 1:
798
+ log->error = log_formatter_error;
799
+ case 0:
800
+ break;
801
+ }
802
+
803
+ env->log = log;
804
+
805
+ return env;
806
+ }
807
+
808
+ STORJ_API int storj_destroy_env(storj_env_t *env)
809
+ {
810
+ int status = 0;
811
+
812
+ // free and destroy all bridge options
813
+ free((char *)env->bridge_options->proto);
814
+ free((char *)env->bridge_options->host);
815
+ free((char *)env->bridge_options->user);
816
+
817
+ // zero out password before freeing
818
+ if (env->bridge_options->pass) {
819
+ unsigned int pass_len = strlen(env->bridge_options->pass);
820
+ if (pass_len > 0) {
821
+ memset_zero((char *)env->bridge_options->pass, pass_len);
822
+ }
823
+ #ifdef _POSIX_MEMLOCK
824
+ status = munlock(env->bridge_options->pass, pass_len);
825
+ #elif _WIN32
826
+ if (!VirtualUnlock((char *)env->bridge_options->pass, pass_len)) {
827
+ status = 1;
828
+ }
829
+ #endif
830
+
831
+ #ifdef _WIN32
832
+ VirtualFree((char *)env->bridge_options, pass_len, MEM_RELEASE);
833
+ #else
834
+ free((char *)env->bridge_options->pass);
835
+ #endif
836
+
837
+ }
838
+
839
+ free(env->bridge_options);
840
+
841
+ // free and destroy all encryption options
842
+ if (env->encrypt_options && env->encrypt_options->mnemonic) {
843
+ unsigned int mnemonic_len = strlen(env->encrypt_options->mnemonic);
844
+
845
+ // zero out file encryption mnemonic before freeing
846
+ if (mnemonic_len > 0) {
847
+ memset_zero((char *)env->encrypt_options->mnemonic, mnemonic_len);
848
+ }
849
+ #ifdef _POSIX_MEMLOCK
850
+ status = munlock(env->encrypt_options->mnemonic, mnemonic_len);
851
+ #elif _WIN32
852
+ if (!VirtualUnlock((char *)env->encrypt_options->mnemonic, mnemonic_len)) {
853
+ status = 1;
854
+ }
855
+ #endif
856
+
857
+ #ifdef _WIN32
858
+ VirtualFree((char *)env->bridge_options, mnemonic_len, MEM_RELEASE);
859
+ #else
860
+ free((char *)env->encrypt_options->mnemonic);
861
+ #endif
862
+ }
863
+
864
+ if (env->tmp_path) {
865
+ free((char *)env->tmp_path);
866
+ }
867
+
868
+ free(env->encrypt_options);
869
+
870
+ // free all http options
871
+ free((char *)env->http_options->user_agent);
872
+ if (env->http_options->proxy_url) {
873
+ free((char *)env->http_options->proxy_url);
874
+ }
875
+ if (env->http_options->cainfo_path) {
876
+ free((char *)env->http_options->cainfo_path);
877
+ }
878
+ free(env->http_options);
879
+
880
+ // free the log levels
881
+ free(env->log);
882
+
883
+ // free the environment
884
+ free(env);
885
+
886
+ curl_global_cleanup();
887
+
888
+ return status;
889
+ }
890
+
891
+ STORJ_API int storj_encrypt_auth(const char *passphrase,
892
+ const char *bridge_user,
893
+ const char *bridge_pass,
894
+ const char *mnemonic,
895
+ char **buffer)
896
+ {
897
+ char *pass_encrypted;
898
+ int pass_length = strlen(bridge_pass);
899
+
900
+ if (encrypt_data(passphrase, bridge_user, bridge_pass,
901
+ &pass_encrypted)) {
902
+ return 1;
903
+ }
904
+
905
+ char *mnemonic_encrypted;
906
+ int mnemonic_length = strlen(mnemonic);
907
+
908
+ if (encrypt_data(passphrase, bridge_user, mnemonic,
909
+ &mnemonic_encrypted)) {
910
+ return 1;
911
+ }
912
+
913
+ struct json_object *body = json_object_new_object();
914
+ json_object *user_str = json_object_new_string(bridge_user);
915
+
916
+ json_object *pass_str = json_object_new_string(pass_encrypted);
917
+ json_object *mnemonic_str = json_object_new_string(mnemonic_encrypted);
918
+
919
+ json_object_object_add(body, "user", user_str);
920
+ json_object_object_add(body, "pass", pass_str);
921
+ json_object_object_add(body, "mnemonic", mnemonic_str);
922
+
923
+ const char *body_str = json_object_to_json_string(body);
924
+
925
+ *buffer = calloc(strlen(body_str) + 1, sizeof(char));
926
+ memcpy(*buffer, body_str, strlen(body_str) + 1);
927
+
928
+ json_object_put(body);
929
+ free(mnemonic_encrypted);
930
+ free(pass_encrypted);
931
+
932
+ return 0;
933
+ }
934
+
935
+ STORJ_API int storj_encrypt_write_auth(const char *filepath,
936
+ const char *passphrase,
937
+ const char *bridge_user,
938
+ const char *bridge_pass,
939
+ const char *mnemonic)
940
+ {
941
+ FILE *fp;
942
+ fp = fopen(filepath, "w");
943
+ if (fp == NULL) {
944
+ return 1;
945
+ }
946
+
947
+ char *buffer = NULL;
948
+ if (storj_encrypt_auth(passphrase, bridge_user,
949
+ bridge_pass, mnemonic, &buffer)) {
950
+ fclose(fp);
951
+ return 1;
952
+ }
953
+
954
+ fwrite(buffer, strlen(buffer), sizeof(char), fp);
955
+ fwrite("\n", 1, sizeof(char), fp);
956
+
957
+ free(buffer);
958
+ fclose(fp);
959
+
960
+ return 0;
961
+ }
962
+
963
+ STORJ_API int storj_decrypt_auth(const char *buffer,
964
+ const char *passphrase,
965
+ char **bridge_user,
966
+ char **bridge_pass,
967
+ char **mnemonic)
968
+ {
969
+ int status = 0;
970
+
971
+ json_object *body = json_tokener_parse(buffer);
972
+
973
+ struct json_object *user_value;
974
+ if (!json_object_object_get_ex(body, "user", &user_value)) {
975
+ status = 1;
976
+ goto clean_up;
977
+ }
978
+
979
+ *bridge_user = strdup((char *)json_object_get_string(user_value));
980
+
981
+ struct json_object *pass_value;
982
+ if (!json_object_object_get_ex(body, "pass", &pass_value)) {
983
+ status = 1;
984
+ goto clean_up;
985
+ }
986
+ char *pass_enc = (char *)json_object_get_string(pass_value);
987
+
988
+ struct json_object *mnemonic_value;
989
+ if (!json_object_object_get_ex(body, "mnemonic", &mnemonic_value)) {
990
+ status = 1;
991
+ goto clean_up;
992
+ }
993
+ char *mnemonic_enc = (char *)json_object_get_string(mnemonic_value);
994
+
995
+ if (decrypt_data(passphrase, *bridge_user, pass_enc, bridge_pass)) {
996
+ status = 1;
997
+ goto clean_up;
998
+ }
999
+
1000
+ if (decrypt_data(passphrase, *bridge_user, mnemonic_enc, mnemonic)) {
1001
+ status = 1;
1002
+ goto clean_up;
1003
+ }
1004
+
1005
+ clean_up:
1006
+ json_object_put(body);
1007
+
1008
+ return status;
1009
+ }
1010
+
1011
+ STORJ_API int storj_decrypt_read_auth(const char *filepath,
1012
+ const char *passphrase,
1013
+ char **bridge_user,
1014
+ char **bridge_pass,
1015
+ char **mnemonic)
1016
+ {
1017
+ FILE *fp;
1018
+ fp = fopen(filepath, "r");
1019
+ if (fp == NULL) {
1020
+ return 1;
1021
+ }
1022
+
1023
+ fseek(fp, 0, SEEK_END);
1024
+ int fsize = ftell(fp);
1025
+ fseek(fp, 0, SEEK_SET);
1026
+
1027
+ char *buffer = calloc(fsize + 1, sizeof(char));
1028
+ if (buffer == NULL) {
1029
+ return 1;
1030
+ }
1031
+
1032
+ int read_blocks = 0;
1033
+ while ((!feof(fp)) && (!ferror(fp))) {
1034
+ read_blocks = fread(buffer + read_blocks, 1, fsize, fp);
1035
+ if (read_blocks <= 0) {
1036
+ break;
1037
+ }
1038
+ }
1039
+
1040
+ int error = ferror(fp);
1041
+ fclose(fp);
1042
+
1043
+ if (error) {
1044
+ return error;
1045
+ }
1046
+
1047
+ int status = storj_decrypt_auth(buffer, passphrase, bridge_user,
1048
+ bridge_pass, mnemonic);
1049
+
1050
+ free(buffer);
1051
+
1052
+ return status;
1053
+
1054
+ }
1055
+
1056
+ STORJ_API uint64_t storj_util_timestamp()
1057
+ {
1058
+ return get_time_milliseconds();
1059
+ }
1060
+
1061
+ STORJ_API int storj_mnemonic_generate(int strength, char **buffer)
1062
+ {
1063
+ return mnemonic_generate(strength, buffer);
1064
+ }
1065
+
1066
+ STORJ_API bool storj_mnemonic_check(const char *mnemonic)
1067
+ {
1068
+ return mnemonic_check(mnemonic);
1069
+ }
1070
+
1071
+ STORJ_API char *storj_strerror(int error_code)
1072
+ {
1073
+ switch(error_code) {
1074
+ case STORJ_BRIDGE_REQUEST_ERROR:
1075
+ return "Bridge request error";
1076
+ case STORJ_BRIDGE_AUTH_ERROR:
1077
+ return "Bridge request authorization error";
1078
+ case STORJ_BRIDGE_TOKEN_ERROR:
1079
+ return "Bridge request token error";
1080
+ case STORJ_BRIDGE_POINTER_ERROR:
1081
+ return "Bridge request pointer error";
1082
+ case STORJ_BRIDGE_REPOINTER_ERROR:
1083
+ return "Bridge request replace pointer error";
1084
+ case STORJ_BRIDGE_TIMEOUT_ERROR:
1085
+ return "Bridge request timeout error";
1086
+ case STORJ_BRIDGE_INTERNAL_ERROR:
1087
+ return "Bridge request internal error";
1088
+ case STORJ_BRIDGE_RATE_ERROR:
1089
+ return "Bridge rate limit error";
1090
+ case STORJ_BRIDGE_BUCKET_NOTFOUND_ERROR:
1091
+ return "Bucket is not found";
1092
+ case STORJ_BRIDGE_FILE_NOTFOUND_ERROR:
1093
+ return "File is not found";
1094
+ case STORJ_BRIDGE_BUCKET_FILE_EXISTS:
1095
+ return "File already exists";
1096
+ case STORJ_BRIDGE_OFFER_ERROR:
1097
+ return "Unable to receive storage offer";
1098
+ case STORJ_BRIDGE_JSON_ERROR:
1099
+ return "Unexpected JSON response";
1100
+ case STORJ_BRIDGE_FILEINFO_ERROR:
1101
+ return "Bridge file info error";
1102
+ case STORJ_FARMER_REQUEST_ERROR:
1103
+ return "Farmer request error";
1104
+ case STORJ_FARMER_EXHAUSTED_ERROR:
1105
+ return "Farmer exhausted error";
1106
+ case STORJ_FARMER_TIMEOUT_ERROR:
1107
+ return "Farmer request timeout error";
1108
+ case STORJ_FARMER_AUTH_ERROR:
1109
+ return "Farmer request authorization error";
1110
+ case STORJ_FARMER_INTEGRITY_ERROR:
1111
+ return "Farmer request integrity error";
1112
+ case STORJ_FILE_INTEGRITY_ERROR:
1113
+ return "File integrity error";
1114
+ case STORJ_FILE_READ_ERROR:
1115
+ return "File read error";
1116
+ case STORJ_FILE_WRITE_ERROR:
1117
+ return "File write error";
1118
+ case STORJ_BRIDGE_FRAME_ERROR:
1119
+ return "Bridge frame request error";
1120
+ case STORJ_FILE_ENCRYPTION_ERROR:
1121
+ return "File encryption error";
1122
+ case STORJ_FILE_SIZE_ERROR:
1123
+ return "File size error";
1124
+ case STORJ_FILE_DECRYPTION_ERROR:
1125
+ return "File decryption error";
1126
+ case STORJ_FILE_GENERATE_HMAC_ERROR:
1127
+ return "File hmac generation error";
1128
+ case STORJ_FILE_SHARD_MISSING_ERROR:
1129
+ return "File missing shard error";
1130
+ case STORJ_FILE_RECOVER_ERROR:
1131
+ return "File recover error";
1132
+ case STORJ_FILE_RESIZE_ERROR:
1133
+ return "File resize error";
1134
+ case STORJ_FILE_UNSUPPORTED_ERASURE:
1135
+ return "File unsupported erasure code error";
1136
+ case STORJ_FILE_PARITY_ERROR:
1137
+ return "File create parity error";
1138
+ case STORJ_META_ENCRYPTION_ERROR:
1139
+ return "Meta encryption error";
1140
+ case STORJ_META_DECRYPTION_ERROR:
1141
+ return "Meta decryption error";
1142
+ case STORJ_TRANSFER_CANCELED:
1143
+ return "File transfer canceled";
1144
+ case STORJ_MEMORY_ERROR:
1145
+ return "Memory error";
1146
+ case STORJ_MAPPING_ERROR:
1147
+ return "Memory mapped file error";
1148
+ case STORJ_UNMAPPING_ERROR:
1149
+ return "Memory mapped file unmap error";
1150
+ case STORJ_QUEUE_ERROR:
1151
+ return "Queue error";
1152
+ case STORJ_HEX_DECODE_ERROR:
1153
+ return "Unable to decode hex string";
1154
+ case STORJ_TRANSFER_OK:
1155
+ return "No errors";
1156
+ default:
1157
+ return "Unknown error";
1158
+ }
1159
+ }
1160
+
1161
+ STORJ_API int storj_bridge_get_info(storj_env_t *env, void *handle, uv_after_work_cb cb)
1162
+ {
1163
+ uv_work_t *work = json_request_work_new(env,"GET", "/", NULL,
1164
+ false, handle);
1165
+ if (!work) {
1166
+ return STORJ_MEMORY_ERROR;
1167
+ }
1168
+
1169
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1170
+ }
1171
+
1172
+ STORJ_API int storj_bridge_get_buckets(storj_env_t *env, void *handle, uv_after_work_cb cb)
1173
+ {
1174
+ uv_work_t *work = uv_work_new();
1175
+ if (!work) {
1176
+ return STORJ_MEMORY_ERROR;
1177
+ }
1178
+ work->data = get_buckets_request_new(env->http_options,
1179
+ env->bridge_options,
1180
+ env->encrypt_options,
1181
+ "GET", "/buckets",
1182
+ NULL, true, handle);
1183
+ if (!work->data) {
1184
+ return STORJ_MEMORY_ERROR;
1185
+ }
1186
+
1187
+ return uv_queue_work(env->loop, (uv_work_t*) work,
1188
+ get_buckets_request_worker, cb);
1189
+ }
1190
+
1191
+ STORJ_API void storj_free_get_buckets_request(get_buckets_request_t *req)
1192
+ {
1193
+ json_object_put(req->response);
1194
+ if (req->buckets && req->total_buckets > 0) {
1195
+ for (int i = 0; i < req->total_buckets; i++) {
1196
+ free((char *)req->buckets[i].name);
1197
+ }
1198
+ }
1199
+ free(req->buckets);
1200
+ free(req);
1201
+ }
1202
+
1203
+ STORJ_API int storj_bridge_create_bucket(storj_env_t *env,
1204
+ const char *name,
1205
+ void *handle,
1206
+ uv_after_work_cb cb)
1207
+ {
1208
+ uv_work_t *work = uv_work_new();
1209
+ if (!work) {
1210
+ return STORJ_MEMORY_ERROR;
1211
+ }
1212
+
1213
+ work->data = create_bucket_request_new(env->http_options,
1214
+ env->bridge_options,
1215
+ env->encrypt_options,
1216
+ name,
1217
+ handle);
1218
+ if (!work->data) {
1219
+ return STORJ_MEMORY_ERROR;
1220
+ }
1221
+
1222
+ return uv_queue_work(env->loop, (uv_work_t*) work,
1223
+ create_bucket_request_worker, cb);
1224
+ }
1225
+
1226
+ STORJ_API int storj_bridge_delete_bucket(storj_env_t *env,
1227
+ const char *id,
1228
+ void *handle,
1229
+ uv_after_work_cb cb)
1230
+ {
1231
+ char *path = str_concat_many(2, "/buckets/", id);
1232
+ if (!path) {
1233
+ return STORJ_MEMORY_ERROR;
1234
+ }
1235
+
1236
+ uv_work_t *work = json_request_work_new(env, "DELETE", path,
1237
+ NULL, true, handle);
1238
+ if (!work) {
1239
+ return STORJ_MEMORY_ERROR;
1240
+ }
1241
+
1242
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1243
+ }
1244
+
1245
+ STORJ_API int storj_bridge_get_bucket(storj_env_t *env,
1246
+ const char *id,
1247
+ void *handle,
1248
+ uv_after_work_cb cb)
1249
+ {
1250
+ uv_work_t *work = uv_work_new();
1251
+ if (!work) {
1252
+ return STORJ_MEMORY_ERROR;
1253
+ }
1254
+
1255
+ char *path = str_concat_many(2, "/buckets/", id);
1256
+ if (!path) {
1257
+ return STORJ_MEMORY_ERROR;
1258
+ }
1259
+
1260
+ work->data = get_bucket_request_new(env->http_options,
1261
+ env->bridge_options,
1262
+ env->encrypt_options,
1263
+ "GET", path,
1264
+ NULL, true, handle);
1265
+ if (!work->data) {
1266
+ return STORJ_MEMORY_ERROR;
1267
+ }
1268
+
1269
+ return uv_queue_work(env->loop, (uv_work_t*) work, get_bucket_request_worker, cb);
1270
+ }
1271
+
1272
+ STORJ_API void storj_free_get_bucket_request(get_bucket_request_t *req)
1273
+ {
1274
+ json_object_put(req->response);
1275
+ free(req->path);
1276
+ if (req->bucket) {
1277
+ free((char *)req->bucket->name);
1278
+ }
1279
+ free(req->bucket);
1280
+ free(req);
1281
+ }
1282
+
1283
+ STORJ_API int storj_bridge_list_files(storj_env_t *env,
1284
+ const char *id,
1285
+ void *handle,
1286
+ uv_after_work_cb cb)
1287
+ {
1288
+ char *path = str_concat_many(3, "/buckets/", id, "/files");
1289
+ if (!path) {
1290
+ return STORJ_MEMORY_ERROR;
1291
+ }
1292
+
1293
+ uv_work_t *work = uv_work_new();
1294
+ if (!work) {
1295
+ return STORJ_MEMORY_ERROR;
1296
+ }
1297
+ work->data = list_files_request_new(env->http_options,
1298
+ env->bridge_options,
1299
+ env->encrypt_options,
1300
+ id, "GET", path,
1301
+ NULL, true, handle);
1302
+
1303
+ if (!work->data) {
1304
+ return STORJ_MEMORY_ERROR;
1305
+ }
1306
+
1307
+ return uv_queue_work(env->loop, (uv_work_t*) work,
1308
+ list_files_request_worker, cb);
1309
+ }
1310
+
1311
+ STORJ_API void storj_free_list_files_request(list_files_request_t *req)
1312
+ {
1313
+ json_object_put(req->response);
1314
+ free(req->path);
1315
+ if (req->files && req->total_files > 0) {
1316
+ for (int i = 0; i < req->total_files; i++) {
1317
+ free((char *)req->files[i].filename);
1318
+ }
1319
+ }
1320
+ free(req->files);
1321
+ free(req);
1322
+ }
1323
+
1324
+ STORJ_API int storj_bridge_create_bucket_token(storj_env_t *env,
1325
+ const char *bucket_id,
1326
+ storj_bucket_op_t operation,
1327
+ void *handle,
1328
+ uv_after_work_cb cb)
1329
+ {
1330
+ struct json_object *body = json_object_new_object();
1331
+ json_object *op_string = json_object_new_string(BUCKET_OP[operation]);
1332
+
1333
+ json_object_object_add(body, "operation", op_string);
1334
+
1335
+ char *path = str_concat_many(3, "/buckets/", bucket_id, "/tokens");
1336
+ if (!path) {
1337
+ return STORJ_MEMORY_ERROR;
1338
+ }
1339
+
1340
+ uv_work_t *work = json_request_work_new(env, "POST", path, body,
1341
+ true, handle);
1342
+ if (!work) {
1343
+ return STORJ_MEMORY_ERROR;
1344
+ }
1345
+
1346
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1347
+ }
1348
+
1349
+ STORJ_API int storj_bridge_get_file_pointers(storj_env_t *env,
1350
+ const char *bucket_id,
1351
+ const char *file_id,
1352
+ void *handle,
1353
+ uv_after_work_cb cb)
1354
+ {
1355
+ char *path = str_concat_many(4, "/buckets/", bucket_id, "/files/", file_id);
1356
+ if (!path) {
1357
+ return STORJ_MEMORY_ERROR;
1358
+ }
1359
+
1360
+ uv_work_t *work = json_request_work_new(env, "GET", path, NULL,
1361
+ true, handle);
1362
+ if (!work) {
1363
+ return STORJ_MEMORY_ERROR;
1364
+ }
1365
+
1366
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1367
+ }
1368
+
1369
+ STORJ_API int storj_bridge_delete_file(storj_env_t *env,
1370
+ const char *bucket_id,
1371
+ const char *file_id,
1372
+ void *handle,
1373
+ uv_after_work_cb cb)
1374
+ {
1375
+ char *path = str_concat_many(4, "/buckets/", bucket_id, "/files/", file_id);
1376
+ if (!path) {
1377
+ return STORJ_MEMORY_ERROR;
1378
+ }
1379
+
1380
+ uv_work_t *work = json_request_work_new(env, "DELETE", path, NULL,
1381
+ true, handle);
1382
+ if (!work) {
1383
+ return STORJ_MEMORY_ERROR;
1384
+ }
1385
+
1386
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1387
+ }
1388
+
1389
+ STORJ_API int storj_bridge_create_frame(storj_env_t *env,
1390
+ void *handle,
1391
+ uv_after_work_cb cb)
1392
+ {
1393
+ uv_work_t *work = json_request_work_new(env, "POST", "/frames", NULL,
1394
+ true, handle);
1395
+ if (!work) {
1396
+ return STORJ_MEMORY_ERROR;
1397
+ }
1398
+
1399
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1400
+ }
1401
+
1402
+ STORJ_API int storj_bridge_get_frames(storj_env_t *env,
1403
+ void *handle,
1404
+ uv_after_work_cb cb)
1405
+ {
1406
+ uv_work_t *work = json_request_work_new(env, "GET", "/frames", NULL,
1407
+ true, handle);
1408
+ if (!work) {
1409
+ return STORJ_MEMORY_ERROR;
1410
+ }
1411
+
1412
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1413
+ }
1414
+
1415
+ STORJ_API int storj_bridge_get_frame(storj_env_t *env,
1416
+ const char *frame_id,
1417
+ void *handle,
1418
+ uv_after_work_cb cb)
1419
+ {
1420
+ char *path = str_concat_many(2, "/frames/", frame_id);
1421
+ if (!path) {
1422
+ return STORJ_MEMORY_ERROR;
1423
+ }
1424
+
1425
+ uv_work_t *work = json_request_work_new(env, "GET", path, NULL,
1426
+ true, handle);
1427
+ if (!work) {
1428
+ return STORJ_MEMORY_ERROR;
1429
+ }
1430
+
1431
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1432
+
1433
+ }
1434
+
1435
+ STORJ_API int storj_bridge_delete_frame(storj_env_t *env,
1436
+ const char *frame_id,
1437
+ void *handle,
1438
+ uv_after_work_cb cb)
1439
+ {
1440
+ char *path = str_concat_many(2, "/frames/", frame_id);
1441
+ if (!path) {
1442
+ return STORJ_MEMORY_ERROR;
1443
+ }
1444
+
1445
+ uv_work_t *work = json_request_work_new(env, "DELETE", path, NULL,
1446
+ true, handle);
1447
+ if (!work) {
1448
+ return STORJ_MEMORY_ERROR;
1449
+ }
1450
+
1451
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1452
+ }
1453
+
1454
+ STORJ_API int storj_bridge_get_file_info(storj_env_t *env,
1455
+ const char *bucket_id,
1456
+ const char *file_id,
1457
+ void *handle,
1458
+ uv_after_work_cb cb)
1459
+ {
1460
+ char *path = str_concat_many(5, "/buckets/", bucket_id, "/files/",
1461
+ file_id, "/info");
1462
+ if (!path) {
1463
+ return STORJ_MEMORY_ERROR;
1464
+ }
1465
+
1466
+ uv_work_t *work = json_request_work_new(env, "GET", path, NULL,
1467
+ true, handle);
1468
+ if (!work) {
1469
+ return STORJ_MEMORY_ERROR;
1470
+ }
1471
+
1472
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1473
+ }
1474
+
1475
+ STORJ_API int storj_bridge_list_mirrors(storj_env_t *env,
1476
+ const char *bucket_id,
1477
+ const char *file_id,
1478
+ void *handle,
1479
+ uv_after_work_cb cb)
1480
+ {
1481
+ char *path = str_concat_many(5, "/buckets/", bucket_id, "/files/",
1482
+ file_id, "/mirrors");
1483
+ if (!path) {
1484
+ return STORJ_MEMORY_ERROR;
1485
+ }
1486
+
1487
+ uv_work_t *work = json_request_work_new(env, "GET", path, NULL,
1488
+ true, handle);
1489
+ if (!work) {
1490
+ return STORJ_MEMORY_ERROR;
1491
+ }
1492
+
1493
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1494
+ }
1495
+
1496
+ STORJ_API int storj_bridge_register(storj_env_t *env,
1497
+ const char *email,
1498
+ const char *password,
1499
+ void *handle,
1500
+ uv_after_work_cb cb)
1501
+ {
1502
+ uint8_t sha256_digest[SHA256_DIGEST_SIZE];
1503
+ sha256_of_str((uint8_t *)password, strlen(password), sha256_digest);
1504
+
1505
+ char *hex_str = hex2str(SHA256_DIGEST_SIZE, sha256_digest);
1506
+ if (!hex_str) {
1507
+ return STORJ_MEMORY_ERROR;
1508
+ }
1509
+
1510
+ struct json_object *body = json_object_new_object();
1511
+ json_object *email_str = json_object_new_string(email);
1512
+ json_object *pass_str = json_object_new_string(hex_str);
1513
+ free(hex_str);
1514
+ json_object_object_add(body, "email", email_str);
1515
+ json_object_object_add(body, "password", pass_str);
1516
+
1517
+ uv_work_t *work = json_request_work_new(env, "POST", "/users", body, true,
1518
+ handle);
1519
+ if (!work) {
1520
+ return STORJ_MEMORY_ERROR;
1521
+ }
1522
+ return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1523
+ }