ruby-libstorj 0.0.0 → 1.0.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.
@@ -284,6 +284,20 @@ typedef struct {
284
284
  void *handle;
285
285
  } get_bucket_request_t;
286
286
 
287
+ /** @brief A structure for queueing get bucket id request work
288
+ */
289
+ typedef struct {
290
+ storj_http_options_t *http_options;
291
+ storj_encrypt_options_t *encrypt_options;
292
+ storj_bridge_options_t *options;
293
+ const char *bucket_name;
294
+ struct json_object *response;
295
+ const char *bucket_id;
296
+ int error_code;
297
+ int status_code;
298
+ void *handle;
299
+ } get_bucket_id_request_t;
300
+
287
301
  /** @brief A structure for that describes a bucket entry/file
288
302
  */
289
303
  typedef struct {
@@ -294,6 +308,7 @@ typedef struct {
294
308
  uint64_t size;
295
309
  const char *hmac;
296
310
  const char *id;
311
+ const char *bucket_id;
297
312
  bool decrypted;
298
313
  const char *index;
299
314
  } storj_file_meta_t;
@@ -317,6 +332,39 @@ typedef struct {
317
332
  void *handle;
318
333
  } list_files_request_t;
319
334
 
335
+ /** @brief A structure for queueing get file info request work
336
+ */
337
+ typedef struct {
338
+ storj_http_options_t *http_options;
339
+ storj_encrypt_options_t *encrypt_options;
340
+ storj_bridge_options_t *options;
341
+ const char *bucket_id;
342
+ char *method;
343
+ char *path;
344
+ bool auth;
345
+ struct json_object *body;
346
+ struct json_object *response;
347
+ storj_file_meta_t *file;
348
+ int error_code;
349
+ int status_code;
350
+ void *handle;
351
+ } get_file_info_request_t;
352
+
353
+ /** @brief A structure for queueing get file id request work
354
+ */
355
+ typedef struct {
356
+ storj_http_options_t *http_options;
357
+ storj_encrypt_options_t *encrypt_options;
358
+ storj_bridge_options_t *options;
359
+ const char *bucket_id;
360
+ const char *file_name;
361
+ struct json_object *response;
362
+ const char *file_id;
363
+ int error_code;
364
+ int status_code;
365
+ void *handle;
366
+ } get_file_id_request_t;
367
+
320
368
  typedef enum {
321
369
  BUCKET_PUSH,
322
370
  BUCKET_PULL
@@ -356,7 +404,7 @@ typedef void (*storj_finished_download_cb)(int status, FILE *fd, void *handle);
356
404
 
357
405
  /** @brief A function signature for an upload complete callback
358
406
  */
359
- typedef void (*storj_finished_upload_cb)(int error_status, char *file_id, void *handle);
407
+ typedef void (*storj_finished_upload_cb)(int error_status, storj_file_meta_t *file, void *handle);
360
408
 
361
409
  /** @brief A structure that represents a pointer to a shard
362
410
  *
@@ -484,7 +532,7 @@ typedef struct {
484
532
  uint32_t shard_concurrency;
485
533
  const char *index;
486
534
  const char *file_name;
487
- char *file_id;
535
+ storj_file_meta_t *info;
488
536
  const char *encrypted_file_name;
489
537
  FILE *original_file;
490
538
  uint64_t file_size;
@@ -758,7 +806,7 @@ STORJ_API int storj_bridge_delete_bucket(storj_env_t *env,
758
806
  * @brief Get a info of specific bucket.
759
807
  *
760
808
  * @param[in] env The storj environment struct
761
- * @param[in] bucket_id The bucket id
809
+ * @param[in] id The bucket id
762
810
  * @param[in] handle A pointer that will be available in the callback
763
811
  * @param[in] cb A function called with response when complete
764
812
  * @return A non-zero error value on failure and 0 on success.
@@ -775,6 +823,20 @@ STORJ_API int storj_bridge_get_bucket(storj_env_t *env,
775
823
  */
776
824
  STORJ_API void storj_free_get_bucket_request(get_bucket_request_t *req);
777
825
 
826
+ /**
827
+ * @brief Get the bucket id by name.
828
+ *
829
+ * @param[in] env The storj environment struct
830
+ * @param[in] name The bucket name
831
+ * @param[in] handle A pointer that will be available in the callback
832
+ * @param[in] cb A function called with response when complete
833
+ * @return A non-zero error value on failure and 0 on success.
834
+ */
835
+ STORJ_API int storj_bridge_get_bucket_id(storj_env_t *env,
836
+ const char *name,
837
+ void *handle,
838
+ uv_after_work_cb cb);
839
+
778
840
  /**
779
841
  * @brief Get a list of all files in a bucket.
780
842
  *
@@ -901,7 +963,7 @@ STORJ_API int storj_bridge_delete_frame(storj_env_t *env,
901
963
  *
902
964
  * @param[in] env The storj environment struct
903
965
  * @param[in] bucket_id The bucket id
904
- * @param[in] file_id The bucket id
966
+ * @param[in] file_id The file id
905
967
  * @param[in] handle A pointer that will be available in the callback
906
968
  * @param[in] cb A function called with response when complete
907
969
  * @return A non-zero error value on failure and 0 on success.
@@ -912,6 +974,29 @@ STORJ_API int storj_bridge_get_file_info(storj_env_t *env,
912
974
  void *handle,
913
975
  uv_after_work_cb cb);
914
976
 
977
+ /**
978
+ * @brief Will free all structs for get file info request
979
+ *
980
+ * @param[in] req - The work request from storj_bridge_get_file_info callback
981
+ */
982
+ STORJ_API void storj_free_get_file_info_request(get_file_info_request_t *req);
983
+
984
+ /**
985
+ * @brief Get the file id by name.
986
+ *
987
+ * @param[in] env The storj environment struct
988
+ * @param[in] bucket_id The bucket id
989
+ * @param[in] file_name The file name
990
+ * @param[in] handle A pointer that will be available in the callback
991
+ * @param[in] cb A function called with response when complete
992
+ * @return A non-zero error value on failure and 0 on success.
993
+ */
994
+ STORJ_API int storj_bridge_get_file_id(storj_env_t *env,
995
+ const char *bucket_id,
996
+ const char *file_name,
997
+ void *handle,
998
+ uv_after_work_cb cb);
999
+
915
1000
  /**
916
1001
  * @brief Get mirror data for a file
917
1002
  *
@@ -953,6 +1038,13 @@ STORJ_API storj_upload_state_t *storj_bridge_store_file(storj_env_t *env,
953
1038
  storj_progress_cb progress_cb,
954
1039
  storj_finished_upload_cb finished_cb);
955
1040
 
1041
+ /**
1042
+ * @brief Will free the file info struct passed to the upload finished callback
1043
+ *
1044
+ * @param[in] file - The storj_file_meta_t struct from storj_finished_upload_cb callback
1045
+ */
1046
+ STORJ_API void storj_free_uploaded_file_info(storj_file_meta_t *file);
1047
+
956
1048
  /**
957
1049
  * @brief Will cancel a download
958
1050
  *
@@ -248,10 +248,6 @@ static void cleanup_state(storj_upload_state_t *state)
248
248
  free(state->frame_id);
249
249
  }
250
250
 
251
- if (state->hmac_id) {
252
- free(state->hmac_id);
253
- }
254
-
255
251
  if (state->encrypted_file_name) {
256
252
  free((char *)state->encrypted_file_name);
257
253
  }
@@ -260,6 +256,10 @@ static void cleanup_state(storj_upload_state_t *state)
260
256
  free(state->exclude);
261
257
  }
262
258
 
259
+ if (state->index) {
260
+ free((char *)state->index);
261
+ }
262
+
263
263
  if (state->encryption_ctr) {
264
264
  free(state->encryption_ctr);
265
265
  }
@@ -286,10 +286,6 @@ static void cleanup_state(storj_upload_state_t *state)
286
286
  free(state->encrypted_file_path);
287
287
  }
288
288
 
289
- if (state->index) {
290
- free((char *)state->index);
291
- }
292
-
293
289
  if (state->shard) {
294
290
  for (int i = 0; i < state->total_shards; i++ ) {
295
291
 
@@ -309,7 +305,7 @@ static void cleanup_state(storj_upload_state_t *state)
309
305
  free(state->shard);
310
306
  }
311
307
 
312
- state->finished_cb(state->error_status, state->file_id, state->handle);
308
+ state->finished_cb(state->error_status, state->info, state->handle);
313
309
 
314
310
  free(state);
315
311
  }
@@ -358,17 +354,36 @@ static void after_create_bucket_entry(uv_work_t *work, int status)
358
354
  req->log->info(state->env->log_options, state->handle,
359
355
  "Successfully Added bucket entry");
360
356
 
357
+ req->log->debug(state->env->log_options, state->handle,
358
+ "fn[after_create_bucket_entry] - JSON Response: %s", json_object_to_json_string(req->response));
359
+
361
360
  state->add_bucket_entry_count = 0;
362
361
  state->completed_upload = true;
363
362
 
363
+ state->info = malloc(sizeof(storj_file_meta_t));
364
+ state->info->created = NULL;
365
+ state->info->filename = state->file_name;
366
+ state->info->mimetype = NULL;
367
+ state->info->erasure = NULL;
368
+ state->info->size = state->file_size;
369
+ state->info->hmac = state->hmac_id;
370
+ state->info->id = NULL;
371
+ state->info->bucket_id = state->bucket_id;
372
+ state->info->decrypted = true;
373
+ state->info->index = strdup(state->index);
374
+
364
375
  struct json_object *file_id_value = NULL;
365
- char *file_id = NULL;
376
+ struct json_object *created_value = NULL;
377
+ struct json_object *mimetype_value = NULL;
378
+
366
379
  if (json_object_object_get_ex(req->response, "id", &file_id_value)) {
367
- file_id = (char *)json_object_get_string(file_id_value);
380
+ state->info->id = strdup((char *)json_object_get_string(file_id_value));
368
381
  }
369
-
370
- if (file_id) {
371
- state->file_id = strdup(file_id);
382
+ if (json_object_object_get_ex(req->response, "created", &created_value)) {
383
+ state->info->created = strdup((char *)json_object_get_string(created_value));
384
+ }
385
+ if (json_object_object_get_ex(req->response, "mimetype", &mimetype_value)) {
386
+ state->info->mimetype = strdup((char *)json_object_get_string(mimetype_value));
372
387
  }
373
388
 
374
389
  } else if (state->add_bucket_entry_count == 6) {
@@ -2133,7 +2148,6 @@ static void verify_bucket_id_callback(uv_work_t *work_req, int status)
2133
2148
  clean_variables:
2134
2149
  queue_next_work(state);
2135
2150
 
2136
- json_object_put(req->response);
2137
2151
  storj_free_get_bucket_request(req);
2138
2152
  free(work_req);
2139
2153
  }
@@ -2460,44 +2474,14 @@ static void prepare_upload_state(uv_work_t *work)
2460
2474
  state->shard[i].work = NULL;
2461
2475
  }
2462
2476
 
2463
- // Get the bucket key to encrypt the filename
2464
- char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
2465
- generate_bucket_key(state->env->encrypt_options->mnemonic,
2466
- state->bucket_id,
2467
- &bucket_key_as_str);
2468
-
2469
- uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
2470
- if (!bucket_key) {
2477
+ if (encrypt_file_name(state->env->encrypt_options->mnemonic,
2478
+ state->bucket_id,
2479
+ state->file_name,
2480
+ (char **)&state->encrypted_file_name)) {
2471
2481
  state->error_status = STORJ_MEMORY_ERROR;
2472
2482
  return;
2473
2483
  }
2474
2484
 
2475
- free(bucket_key_as_str);
2476
-
2477
- // Get file name encryption key with first half of hmac w/ magic
2478
- struct hmac_sha512_ctx ctx1;
2479
- hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
2480
- hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
2481
- uint8_t key[SHA256_DIGEST_SIZE];
2482
- hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
2483
-
2484
- // Generate the synthetic iv with first half of hmac w/ bucket and filename
2485
- struct hmac_sha512_ctx ctx2;
2486
- hmac_sha512_set_key(&ctx2, SHA256_DIGEST_SIZE, bucket_key);
2487
- hmac_sha512_update(&ctx2, strlen(state->bucket_id),
2488
- (uint8_t *)state->bucket_id);
2489
- hmac_sha512_update(&ctx2, strlen(state->file_name),
2490
- (uint8_t *)state->file_name);
2491
- uint8_t filename_iv[SHA256_DIGEST_SIZE];
2492
- hmac_sha512_digest(&ctx2, SHA256_DIGEST_SIZE, filename_iv);
2493
-
2494
- free(bucket_key);
2495
-
2496
- char *encrypted_file_name;
2497
- encrypt_meta(state->file_name, key, filename_iv, &encrypted_file_name);
2498
-
2499
- state->encrypted_file_name = encrypted_file_name;
2500
-
2501
2485
  uint8_t *index = NULL;
2502
2486
  char *key_as_str = NULL;
2503
2487
 
@@ -2663,7 +2647,7 @@ STORJ_API storj_upload_state_t *storj_bridge_store_file(storj_env_t *env,
2663
2647
  } else {
2664
2648
  state->index = NULL;
2665
2649
  }
2666
- state->file_id = NULL;
2650
+ state->info = NULL;
2667
2651
  state->file_name = opts->file_name;
2668
2652
  state->encrypted_file_name = NULL;
2669
2653
  state->original_file = opts->fd;
@@ -2734,3 +2718,15 @@ STORJ_API storj_upload_state_t *storj_bridge_store_file(storj_env_t *env,
2734
2718
  }
2735
2719
  return state;
2736
2720
  }
2721
+
2722
+ STORJ_API void storj_free_uploaded_file_info(storj_file_meta_t *file)
2723
+ {
2724
+ if (file) {
2725
+ free((char *)file->id);
2726
+ free((char *)file->created);
2727
+ free((char *)file->mimetype);
2728
+ free((char *)file->hmac);
2729
+ free((char *)file->index);
2730
+ }
2731
+ free(file);
2732
+ }
@@ -80,6 +80,54 @@ char *str_concat_many(int count, ...)
80
80
  return combined;
81
81
  }
82
82
 
83
+ char *str_replace(char *search, char *replace, char *subject) {
84
+ char *result; // the return string
85
+ char *ins; // the next insert point
86
+ char *tmp; // varies
87
+ size_t len_search; // length of search (the string to remove)
88
+ size_t len_replace; // length of replace (the string to replace search with)
89
+ size_t len_front; // distance between search and end of last replace
90
+ int count; // number of replacements
91
+
92
+ // sanity checks and initialization
93
+ if (!subject || !search)
94
+ return NULL;
95
+ len_search = strlen(search);
96
+ if (len_search == 0)
97
+ return NULL; // empty search causes infinite loop during count
98
+ if (!replace)
99
+ replace = "";
100
+ len_replace = strlen(replace);
101
+
102
+ // count the number of replacements needed
103
+ ins = subject;
104
+ tmp = strstr(ins, search);
105
+ for (count = 0; tmp != NULL; ++count) {
106
+ ins = tmp + len_search;
107
+ tmp = strstr(ins, search);
108
+ }
109
+
110
+ tmp = result = malloc(strlen(subject) + (len_replace - len_search) * count + 1);
111
+
112
+ if (!result)
113
+ return NULL;
114
+
115
+ // first time through the loop, all the variable are set correctly
116
+ // from here on,
117
+ // tmp points to the end of the result string
118
+ // ins points to the next occurrence of search in subject
119
+ // orig points to the remainder of subject after "end of search"
120
+ while (count--) {
121
+ ins = strstr(subject, search);
122
+ len_front = ins - subject;
123
+ tmp = strncpy(tmp, subject, len_front) + len_front;
124
+ tmp = strcpy(tmp, replace) + len_replace;
125
+ subject += len_front + len_search; // move to next "end of search"
126
+ }
127
+ strcpy(tmp, subject);
128
+ return result;
129
+ }
130
+
83
131
  void random_buffer(uint8_t *buf, size_t len)
84
132
  {
85
133
  static FILE *frand = NULL;
@@ -48,6 +48,18 @@ uint8_t *str2hex(size_t length, char *data);
48
48
 
49
49
  char *str_concat_many(int count, ...);
50
50
 
51
+ /**
52
+ * @brief Replace all occurrences of the search string with the replacement string
53
+ *
54
+ * The result string from this function must be freed.
55
+ *
56
+ * @param[in] search The value being searched for, otherwise known as the needle
57
+ * @param[in] replace The replacement value that replaces found search values
58
+ * @param[in] subject The string being searched and replaced on, otherwise known as the haystack.
59
+ * @return A null value on error, otherwise a string with replaced values.
60
+ */
61
+ char *str_replace(char *search, char *replace, char *subject);
62
+
51
63
  void random_buffer(uint8_t *buf, size_t len);
52
64
 
53
65
  uint64_t shard_size(int hops);
@@ -90,7 +90,12 @@ int mock_bridge_server(void *cls,
90
90
  page = get_response_string(responses, "getbucket");
91
91
  status_code = MHD_HTTP_OK;
92
92
  }
93
- } else if (0 == strcmp(url, "/buckets/368be0816766b28fd5f43af5/files")) {
93
+ } else if (0 == strcmp(url, "/bucket-ids/g9qacwq2AE1+5nzL/HYyYdY9WoIr+1ueOuVEx6/IzzZKK9sULoKDDdYvhOpavHH2P3xQNw==")) {
94
+ if (check_auth(user, pass, &status_code, page)) {
95
+ page = get_response_string(responses, "getbucketid");
96
+ status_code = MHD_HTTP_OK;
97
+ }
98
+ } else if (0 == strcmp(url, "/buckets/368be0816766b28fd5f43af5/files")) {
94
99
  if (check_auth(user, pass, &status_code, page)) {
95
100
  page = get_response_string(responses, "listfiles");
96
101
  status_code = MHD_HTTP_OK;
@@ -100,6 +105,11 @@ int mock_bridge_server(void *cls,
100
105
  page = get_response_string(responses, "getfileinfo");
101
106
  status_code = MHD_HTTP_OK;
102
107
  }
108
+ } else if (0 == strcmp(url, "/buckets/368be0816766b28fd5f43af5/file-ids/QR6/qHizNFm+t+4vSvr575xVp2R3/rC/qFlmOH10HsdGQtofpUUqwEdaZUJI0jPIImYMZFu6cZDrMIvJtcK3pHAb+kkPv0Y5")) {
109
+ if (check_auth(user, pass, &status_code, page)) {
110
+ page = get_response_string(responses, "getfileid");
111
+ status_code = MHD_HTTP_OK;
112
+ }
103
113
  } else if (0 == strcmp(url, "/buckets/368be0816766b28fd5f43af5/file-ids/hTY5wsqYyLJQppCMiFQI7v2n/IZZiKb0ES1RCrUqK7Fe5m0/+fYwh+E/vp8M3FCEECle63BhlWlHi/Hj/Yg5y/bIjy8SxQ==")) {
104
114
  if (check_auth(user, pass, &status_code, page)) {
105
115
  status_code = MHD_HTTP_NOT_FOUND;
@@ -23,6 +23,9 @@
23
23
  "name": "g9qacwq2AE1+5nzL/HYyYdY9WoIr+1ueOuVEx6/IzzZKK9sULoKDDdYvhOpavHH2P3xQNw==",
24
24
  "id": "368be0816766b28fd5f43af5"
25
25
  },
26
+ "getbucketid": {
27
+ "id": "368be0816766b28fd5f43af5"
28
+ },
26
29
  "putbuckets": {
27
30
  "user": "user@sample.com",
28
31
  "encryptionKey": "",
@@ -26,6 +26,10 @@ storj_encrypt_options_t encrypt_options = {
26
26
  .mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
27
27
  };
28
28
 
29
+ storj_encrypt_options_t encrypt_options_null_mnemonic = {
30
+ .mnemonic = NULL
31
+ };
32
+
29
33
  storj_http_options_t http_options = {
30
34
  .user_agent = "storj-test",
31
35
  .low_speed_limit = 0,
@@ -99,6 +103,20 @@ void check_get_bucket(uv_work_t *work_req, int status)
99
103
  free(work_req);
100
104
  }
101
105
 
106
+ void check_get_bucket_id(uv_work_t *work_req, int status)
107
+ {
108
+ assert(status == 0);
109
+ get_bucket_id_request_t *req = work_req->data;
110
+ assert(req->handle == NULL);
111
+ assert(strcmp(req->bucket_id, "368be0816766b28fd5f43af5") == 0);
112
+
113
+ pass("storj_bridge_get_bucket_id");
114
+
115
+ json_object_put(req->response);
116
+ free(req);
117
+ free(work_req);
118
+ }
119
+
102
120
  void check_get_buckets_badauth(uv_work_t *work_req, int status)
103
121
  {
104
122
  assert(status == 0);
@@ -188,6 +206,20 @@ void check_list_files_badauth(uv_work_t *work_req, int status)
188
206
  free(work_req);
189
207
  }
190
208
 
209
+ void check_get_file_id(uv_work_t *work_req, int status)
210
+ {
211
+ assert(status == 0);
212
+ get_file_id_request_t *req = work_req->data;
213
+ assert(req->handle == NULL);
214
+ assert(strcmp(req->file_id, "998960317b6725a3f8080c2b") == 0);
215
+
216
+ pass("storj_bridge_get_file_id");
217
+
218
+ json_object_put(req->response);
219
+ free(req);
220
+ free(work_req);
221
+ }
222
+
191
223
  void check_bucket_tokens(uv_work_t *work_req, int status)
192
224
  {
193
225
  assert(status == 0);
@@ -261,6 +293,18 @@ void check_resolve_file(int status, FILE *fd, void *handle)
261
293
  }
262
294
  }
263
295
 
296
+ void check_resolve_file_null_mnemonic(int status, FILE *fd, void *handle)
297
+ {
298
+ fclose(fd);
299
+ assert(handle == NULL);
300
+ if (status == STORJ_FILE_DECRYPTION_ERROR) {
301
+ pass("storj_bridge_resolve_file_null_mnemonic");
302
+ } else {
303
+ fail("storj_bridge_resolve_file_null_mnemonic");
304
+ printf("Status: %d\n", status);
305
+ }
306
+ }
307
+
264
308
  void check_resolve_file_cancel(int status, FILE *fd, void *handle)
265
309
  {
266
310
  fclose(fd);
@@ -283,11 +327,11 @@ void check_store_file_progress(double progress,
283
327
  }
284
328
  }
285
329
 
286
- void check_store_file(int error_code, char *file_id, void *handle)
330
+ void check_store_file(int error_code, storj_file_meta_t *file, void *handle)
287
331
  {
288
332
  assert(handle == NULL);
289
333
  if (error_code == 0) {
290
- if (strcmp(file_id, "85fb0ed00de1196dc22e0f6d") == 0 ) {
334
+ if (file && strcmp(file->id, "85fb0ed00de1196dc22e0f6d") == 0 ) {
291
335
  pass("storj_bridge_store_file");
292
336
  } else {
293
337
  fail("storj_bridge_store_file(0)");
@@ -297,10 +341,10 @@ void check_store_file(int error_code, char *file_id, void *handle)
297
341
  printf("\t\tERROR: %s\n", storj_strerror(error_code));
298
342
  }
299
343
 
300
- free(file_id);
344
+ storj_free_uploaded_file_info(file);
301
345
  }
302
346
 
303
- void check_store_file_cancel(int error_code, char *file_id, void *handle)
347
+ void check_store_file_cancel(int error_code, storj_file_meta_t *file, void *handle)
304
348
  {
305
349
  assert(handle == NULL);
306
350
  if (error_code == STORJ_TRANSFER_CANCELED) {
@@ -310,7 +354,7 @@ void check_store_file_cancel(int error_code, char *file_id, void *handle)
310
354
  printf("\t\tERROR: %s\n", storj_strerror(error_code));
311
355
  }
312
356
 
313
- free(file_id);
357
+ storj_free_uploaded_file_info(file);
314
358
  }
315
359
 
316
360
  void check_delete_file(uv_work_t *work_req, int status)
@@ -412,22 +456,15 @@ void check_delete_frame(uv_work_t *work_req, int status)
412
456
  void check_file_info(uv_work_t *work_req, int status)
413
457
  {
414
458
  assert(status == 0);
415
- json_request_t *req = work_req->data;
459
+ get_file_info_request_t *req = work_req->data;
416
460
  assert(req->handle == NULL);
461
+ assert(req->file);
462
+ assert(strcmp(req->file->filename, "storj-test-download.data") == 0);
463
+ assert(strcmp(req->file->mimetype, "video/ogg") == 0);
417
464
 
418
- struct json_object *value;
419
- int success = json_object_object_get_ex(req->response, "mimetype", &value);
420
- assert(success == 1);
421
- assert(json_object_is_type(value, json_type_string) == 1);
422
-
423
- const char* mimetype = json_object_get_string(value);
424
-
425
- assert(strcmp(mimetype, "video/ogg") == 0);
426
465
  pass("storj_bridge_get_file_info");
427
466
 
428
- json_object_put(req->response);
429
- free(req->path);
430
- free(req);
467
+ storj_free_get_file_info_request(req);
431
468
  free(work_req);
432
469
  }
433
470
 
@@ -614,12 +651,12 @@ int test_upload_cancel()
614
651
  return 0;
615
652
  }
616
653
 
617
- int test_download()
654
+ int _test_download(storj_encrypt_options_t *encrypt_options, void *cb_finished)
618
655
  {
619
656
 
620
657
  // initialize event loop and environment
621
658
  storj_env_t *env = storj_init_env(&bridge_options,
622
- &encrypt_options,
659
+ encrypt_options,
623
660
  &http_options,
624
661
  &log_options);
625
662
  assert(env != NULL);
@@ -639,7 +676,7 @@ int test_download()
639
676
  download_fp,
640
677
  NULL,
641
678
  check_resolve_file_progress,
642
- check_resolve_file);
679
+ cb_finished);
643
680
 
644
681
  if (!state || state->error_status != 0) {
645
682
  return 1;
@@ -656,6 +693,16 @@ int test_download()
656
693
  return 0;
657
694
  }
658
695
 
696
+ int test_download()
697
+ {
698
+ return _test_download(&encrypt_options, check_resolve_file);
699
+ }
700
+
701
+ int test_download_null_mnemonic()
702
+ {
703
+ return _test_download(&encrypt_options_null_mnemonic, check_resolve_file_null_mnemonic);
704
+ }
705
+
659
706
  int test_download_cancel()
660
707
  {
661
708
 
@@ -775,6 +822,10 @@ int test_api()
775
822
  status = storj_bridge_get_bucket(env, bucket_id, NULL, check_get_bucket);
776
823
  assert(status == 0);
777
824
 
825
+ // get bucket id
826
+ status = storj_bridge_get_bucket_id(env, "test", NULL, check_get_bucket_id);
827
+ assert(status == 0);
828
+
778
829
  // create a new bucket with a name
779
830
  status = storj_bridge_create_bucket(env, "backups", NULL,
780
831
  check_create_bucket);
@@ -791,6 +842,11 @@ int test_api()
791
842
  check_list_files);
792
843
  assert(status == 0);
793
844
 
845
+ // get file id
846
+ status = storj_bridge_get_file_id(env, bucket_id, "storj-test-download.data",
847
+ NULL, check_get_file_id);
848
+ assert(status == 0);
849
+
794
850
  // create bucket tokens
795
851
  status = storj_bridge_create_bucket_token(env,
796
852
  bucket_id,
@@ -1106,6 +1162,31 @@ int test_generate_seed_256_trezor()
1106
1162
  return 0;
1107
1163
  }
1108
1164
 
1165
+ int test_generate_seed_null_mnemonic()
1166
+ {
1167
+ char *mnemonic = NULL;
1168
+ char *seed = calloc(128 + 1, sizeof(char));
1169
+ char *expected_seed = "4ed8d4b17698ddeaa1f1559f152f87b5d472f725ca86d341bd0276f1b61197e21dd5a391f9f5ed7340ff4d4513aab9cce44f9497a5e7ed85fd818876b6eb402e";
1170
+
1171
+ mnemonic_to_seed(mnemonic, "", &seed);
1172
+ seed[128] = '\0';
1173
+
1174
+ int check = memcmp(seed, expected_seed, 128);
1175
+ if (check != 0) {
1176
+ fail("test_generate_seed");
1177
+ printf("\t\texpected seed: %s\n", expected_seed);
1178
+ printf("\t\tactual seed: %s\n", seed);
1179
+
1180
+ free(seed);
1181
+ return 1;
1182
+ }
1183
+
1184
+ free(seed);
1185
+ pass("test_generate_seed_null_mnemonic");
1186
+
1187
+ return 0;
1188
+ }
1189
+
1109
1190
  int test_generate_bucket_key()
1110
1191
  {
1111
1192
  char *mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
@@ -1524,6 +1605,34 @@ int test_memory_mapping()
1524
1605
  return 0;
1525
1606
  }
1526
1607
 
1608
+ int test_str_replace()
1609
+ {
1610
+ char *subject = "g9qacwq2AE1+5nzL/HYyYdY9WoIr+1ueOuVEx6/IzzZKK9sULoKDDdYvhOpavHH2P3xQNw==";
1611
+
1612
+ char *result = str_replace("/", "%2F", subject);
1613
+ if (!result) {
1614
+ fail("test_str_replace");
1615
+ return 0;
1616
+ }
1617
+
1618
+ char *expected = "g9qacwq2AE1+5nzL%2FHYyYdY9WoIr+1ueOuVEx6%2FIzzZKK9sULoKDDdYvhOpavHH2P3xQNw==";
1619
+
1620
+ int failed = 0;
1621
+ if (strcmp(expected, result) != 0) {
1622
+ failed = 1;
1623
+ }
1624
+
1625
+ if (failed) {
1626
+ fail("test_str_replace");
1627
+ } else {
1628
+ pass("test_str_replace");
1629
+ }
1630
+
1631
+ free(result);
1632
+
1633
+ return 0;
1634
+ }
1635
+
1527
1636
  // Test Bridge Server
1528
1637
  struct MHD_Daemon *start_test_server()
1529
1638
  {
@@ -1569,6 +1678,7 @@ int main(void)
1569
1678
 
1570
1679
  printf("Test Suite: Downloads\n");
1571
1680
  test_download();
1681
+ test_download_null_mnemonic();
1572
1682
  test_download_cancel();
1573
1683
  printf("\n");
1574
1684
 
@@ -1580,6 +1690,7 @@ int main(void)
1580
1690
  test_generate_seed();
1581
1691
  test_generate_seed_256();
1582
1692
  test_generate_seed_256_trezor();
1693
+ test_generate_seed_null_mnemonic();
1583
1694
  printf("\n");
1584
1695
 
1585
1696
  printf("Test Suite: Crypto\n");
@@ -1596,6 +1707,7 @@ int main(void)
1596
1707
  test_get_time_milliseconds();
1597
1708
  test_determine_shard_size();
1598
1709
  test_memory_mapping();
1710
+ test_str_replace();
1599
1711
 
1600
1712
  int num_failed = tests_ran - test_status;
1601
1713
  printf(KGRN "\nPASSED: %i" RESET, test_status);