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.
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @file storjapi_callback.h
3
+ * @brief Storj callback library.
4
+ *
5
+ * Implements callback functionality that can be customised for
6
+ * end user's application
7
+ */
8
+
9
+ #ifndef CLI_CALLBACK_H
10
+ #define CLI_CALLBACK_H
11
+
12
+ #ifdef __cplusplus
13
+ extern "C" {
14
+ #endif
15
+
16
+ #include "storj.h"
17
+
18
+ #define CLI_NO_SUCH_FILE_OR_DIR 0x00
19
+ #define CLI_VALID_REGULAR_FILE 0x01
20
+ #define CLI_VALID_DIR 0x02
21
+ #define CLI_UNKNOWN_FILE_ATTR 0x03
22
+ #define CLI_UPLOAD_FILE_LOG_ERR 0x04
23
+
24
+ /**
25
+ * @brief A Structure for passing the User's Application info to
26
+ * Storj API.
27
+ */
28
+ typedef struct cli_api {
29
+ storj_env_t *env;
30
+ char *bucket_name;
31
+ char bucket_id[256];
32
+ char *file_name;
33
+ char file_id[256];
34
+ char *file_path; /**< local upload files directory path */
35
+ FILE *src_fd;
36
+ char src_list[256]; /**< file list ready to upload */
37
+ char *src_file; /**< next file ready to upload */
38
+ FILE *dst_fd;
39
+ char *dst_file; /**< next file ready to upload */
40
+ int xfer_count; /**< # of files xferred (up/down) */
41
+ int total_files; /**< total files to upload */
42
+ char *last_cmd_req; /**< last command requested */
43
+ char *curr_cmd_req; /**< cli curr command requested */
44
+ char *next_cmd_req; /**< cli curr command requested */
45
+ char *final_cmd_req; /**< final command in the seq */
46
+ char *excp_cmd_resp; /**< expected cmd response */
47
+ char *rcvd_cmd_resp; /**< received cmd response */
48
+ int error_status; /**< command response/error status */
49
+ storj_log_levels_t *log;
50
+ void *handle;
51
+ } cli_api_t;
52
+
53
+ /**
54
+ * @brief Callback function listing bucket names & IDs
55
+ */
56
+ void get_buckets_callback(uv_work_t *work_req, int status);
57
+
58
+ /**
59
+ * @brief Callback function returning the bucket id for a given
60
+ * bucket name
61
+ */
62
+ void get_bucket_id_callback(uv_work_t *work_req, int status);
63
+
64
+ /**
65
+ * @brief Callback function returning the file id for a given
66
+ * file name
67
+ */
68
+ void get_file_id_callback(uv_work_t *work_req, int status);
69
+
70
+ /**
71
+ * @brief Storj api state machine function
72
+ */
73
+ void queue_next_cmd_req(cli_api_t *cli_api);
74
+
75
+ /**
76
+ * @brief Function lists the bucket names & IDs
77
+ *
78
+ * @param[in] cli_api_t structure that passes user's input
79
+ * info
80
+ * @return A non-zero error value on failure and 0 on success.
81
+ */
82
+ int cli_list_buckets(cli_api_t *cli_api);
83
+
84
+ /**
85
+ * @brief Function returns the corresponding bucket's id for a
86
+ * given bucket name
87
+ *
88
+ * @param[in] cli_api_t structure that passes user's input
89
+ * info
90
+ * @return A non-zero error value on failure and 0 on success.
91
+ */
92
+ int cli_get_bucket_id(cli_api_t *cli_api);
93
+
94
+ /**
95
+ * @brief Function to list files in a given bucket name
96
+ *
97
+ * @param[in] cli_api_t structure that passes user's input
98
+ * info
99
+ * @return A non-zero error value on failure and 0 on success.
100
+ */
101
+ int cli_list_files(cli_api_t *cli_api);
102
+
103
+ /**
104
+ * @brief Function to remove a given bucket name
105
+ *
106
+ * @param[in] cli_api_t structure that passes user's input
107
+ * info
108
+ * @return A non-zero error value on failure and 0 on success.
109
+ */
110
+ int cli_remove_bucket(cli_api_t *cli_api);
111
+
112
+ /**
113
+ * @brief Function to remove a file from a given bucket name
114
+ *
115
+ * @param[in] cli_api_t structure that passes user's input
116
+ * info
117
+ * @return A non-zero error value on failure and 0 on success.
118
+ */
119
+ int cli_remove_file(cli_api_t *cli_api);
120
+
121
+ /**
122
+ * @brief Function to return the node IDs for a given file for a
123
+ * given bucket name
124
+ *
125
+ * @param[in] cli_api_t structure that passes user's input
126
+ * info
127
+ * @return A non-zero error value on failure and 0 on success.
128
+ */
129
+ int cli_list_mirrors(cli_api_t *cli_api);
130
+
131
+ /**
132
+ * @brief Function to upload a local file into a given bucket
133
+ * name
134
+ *
135
+ * @param[in] cli_api_t structure that passes user's input
136
+ * info
137
+ * @return A non-zero error value on failure and 0 on success.
138
+ */
139
+ int cli_upload_file(cli_api_t *cli_api);
140
+
141
+ /**
142
+ * @brief Function to upload local files into a given bucket
143
+ * name
144
+ *
145
+ * @param[in] cli_api_t structure that passes user's input
146
+ * info
147
+ * @return A non-zero error value on failure and 0 on success.
148
+ */
149
+ int cli_upload_files(cli_api_t *cli_api);
150
+
151
+ /**
152
+ * @brief Function to download a file from a given bucket to a
153
+ * local folder
154
+ *
155
+ * @param[in] cli_api_t structure that passes user's input
156
+ * info
157
+ * @return A non-zero error value on failure and 0 on success.
158
+ */
159
+ int cli_download_file(cli_api_t *cli_api);
160
+
161
+ /**
162
+ * @brief Function to download files from a given bucket to a
163
+ * local folder
164
+ *
165
+ * @param[in] cli_api_t structure that passes user's input
166
+ * info
167
+ * @return A non-zero error value on failure and 0 on success.
168
+ */
169
+ int cli_download_files(cli_api_t *cli_api);
170
+
171
+ #ifdef __cplusplus
172
+ }
173
+ #endif
174
+
175
+ #endif /* CLI_CALLBACK_H */
@@ -141,6 +141,98 @@ cleanup:
141
141
  return status;
142
142
  }
143
143
 
144
+ int decrypt_bucket_name(const char *mnemonic, const char *encrypted_name, char **decrypted_name) {
145
+ return decrypt_file_name(mnemonic, BUCKET_NAME_MAGIC, encrypted_name, decrypted_name);
146
+ }
147
+
148
+ int decrypt_file_name(const char *mnemonic, const char* bucket_id,
149
+ const char *encrypted_name, char **decrypted_name) {
150
+ int status = 0;
151
+
152
+ // Derive a key based on the bucket id
153
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
154
+ generate_bucket_key(mnemonic, bucket_id, &bucket_key_as_str);
155
+
156
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
157
+ if (!bucket_key) {
158
+ status = 1;
159
+ goto cleanup;
160
+ }
161
+
162
+ // Get encryption key with first half of hmac w/ magic
163
+ struct hmac_sha512_ctx ctx1;
164
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
165
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
166
+ uint8_t key[SHA256_DIGEST_SIZE];
167
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
168
+
169
+ status = decrypt_meta(encrypted_name, key, decrypted_name);
170
+
171
+ cleanup:
172
+
173
+ if (bucket_key) {
174
+ memset_zero(bucket_key, BASE16_DECODE_LENGTH(strlen(bucket_key_as_str)) + 1);
175
+ free(bucket_key);
176
+ }
177
+ if (bucket_key_as_str) {
178
+ memset_zero(bucket_key_as_str, DETERMINISTIC_KEY_SIZE + 1);
179
+ free(bucket_key_as_str);
180
+ }
181
+
182
+ return status;
183
+ }
184
+
185
+ int encrypt_bucket_name(const char *mnemonic, const char *bucket_name, char **encrypted_name) {
186
+ return encrypt_file_name(mnemonic, BUCKET_NAME_MAGIC, bucket_name, encrypted_name);
187
+ }
188
+
189
+ int encrypt_file_name(const char *mnemonic, const char* bucket_id,
190
+ const char *file_name, char **encrypted_name) {
191
+ int status = 0;
192
+
193
+ // Derive a key based on the bucket id
194
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
195
+ generate_bucket_key(mnemonic, bucket_id, &bucket_key_as_str);
196
+
197
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
198
+ if (!bucket_key) {
199
+ status = 1;
200
+ goto cleanup;
201
+ }
202
+
203
+ // Get encryption key with first half of hmac w/ magic
204
+ struct hmac_sha512_ctx ctx1;
205
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
206
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
207
+ uint8_t key[SHA256_DIGEST_SIZE];
208
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
209
+
210
+ // Generate the synthetic iv with first half of hmac w/ bucket and filename
211
+ struct hmac_sha512_ctx ctx2;
212
+ hmac_sha512_set_key(&ctx2, SHA256_DIGEST_SIZE, bucket_key);
213
+ if (strcmp(bucket_id, BUCKET_NAME_MAGIC)) {
214
+ hmac_sha512_update(&ctx2, strlen(bucket_id), (uint8_t *) bucket_id);
215
+ }
216
+ hmac_sha512_update(&ctx2, strlen(file_name), (uint8_t *)file_name);
217
+ uint8_t iv[SHA256_DIGEST_SIZE];
218
+ hmac_sha512_digest(&ctx2, SHA256_DIGEST_SIZE, iv);
219
+
220
+ status = encrypt_meta(file_name, key, iv, encrypted_name);
221
+
222
+ cleanup:
223
+
224
+ if (bucket_key) {
225
+ memset_zero(bucket_key, BASE16_DECODE_LENGTH(strlen(bucket_key_as_str)) + 1);
226
+ free(bucket_key);
227
+ }
228
+ if (bucket_key_as_str) {
229
+ memset_zero(bucket_key_as_str, DETERMINISTIC_KEY_SIZE + 1);
230
+ free(bucket_key_as_str);
231
+ }
232
+
233
+ return status;
234
+ }
235
+
144
236
  int get_deterministic_key(const char *key, int key_len,
145
237
  const char *id, char **buffer)
146
238
  {
@@ -462,18 +554,20 @@ int decrypt_meta(const char *buffer_base64,
462
554
  if (!base64_decode_update(&ctx3, &decode_len, buffer,
463
555
  strlen(buffer_base64), (uint8_t *)buffer_base64)) {
464
556
  free(buffer);
465
- return 1;
557
+ //STORJ_META_DECRYPTION_ERROR
558
+ return 6001;
466
559
  }
467
560
 
468
561
  if (!base64_decode_final(&ctx3)) {
469
562
  free(buffer);
470
- return 1;
563
+ //STORJ_META_DECRYPTION_ERROR
564
+ return 6001;
471
565
  }
472
566
 
473
567
  if (GCM_DIGEST_SIZE + SHA256_DIGEST_SIZE + 1 > decode_len) {
474
568
  free(buffer);
475
569
  //STORJ_META_DECRYPTION_ERROR
476
- return 1;
570
+ return 6001;
477
571
  }
478
572
 
479
573
  size_t length = decode_len - GCM_DIGEST_SIZE - SHA256_DIGEST_SIZE;
@@ -511,7 +605,7 @@ int decrypt_meta(const char *buffer_base64,
511
605
  int digest_match = memcmp(actual_digest, digest, GCM_DIGEST_SIZE);
512
606
  if (digest_match != 0) {
513
607
  //STORJ_META_DECRYPTION_ERROR
514
- return 1;
608
+ return 6001;
515
609
  }
516
610
 
517
611
  *filemeta = calloc(length + 1, sizeof(char));
@@ -71,6 +71,57 @@ int generate_file_key(const char *mnemonic,
71
71
  const char *index,
72
72
  char **file_key);
73
73
 
74
+ /**
75
+ * @brief Decrypt a bucket name
76
+ *
77
+ * @param[in] mnemonic Character array of the mnemonic
78
+ * @param[in] encrypted_name Character array of the encrypted name
79
+ * @param[out] decrypted_name Character array of the decrypted name
80
+ * @return A non-zero error value on failure and 0 on success.
81
+ */
82
+ int decrypt_bucket_name(const char *mnemonic,
83
+ const char *encrypted_name,
84
+ char **decrypted_name);
85
+
86
+ /**
87
+ * @brief Decrypt a file name
88
+ *
89
+ * @param[in] mnemonic Character array of the mnemonic
90
+ * @param[in] bucket_id Character array of bucket id
91
+ * @param[in] encrypted_name Character array of the encrypted name
92
+ * @param[out] decrypted_name Character array of the decrypted name
93
+ * @return A non-zero error value on failure and 0 on success.
94
+ */
95
+ int decrypt_file_name(const char *mnemonic,
96
+ const char *bucket_id,
97
+ const char *encrypted_name,
98
+ char **decrypted_name);
99
+ /**
100
+ * @brief Encrypt a bucket name
101
+ *
102
+ * @param[in] mnemonic Character array of the mnemonic
103
+ * @param[in] bucket_name Character array of the bucket name
104
+ * @param[out] encrypted_name Character array of the encrypted name
105
+ * @return A non-zero error value on failure and 0 on success.
106
+ */
107
+ int encrypt_bucket_name(const char *mnemonic,
108
+ const char *bucket_name,
109
+ char **encrypted_name);
110
+
111
+ /**
112
+ * @brief Encrypt a file name
113
+ *
114
+ * @param[in] mnemonic Character array of the mnemonic
115
+ * @param[in] bucket_id Character array of bucket id
116
+ * @param[in] file_name Character array of the file name
117
+ * @param[out] encrypted_name Character array of the encrypted name
118
+ * @return A non-zero error value on failure and 0 on success.
119
+ */
120
+ int encrypt_file_name(const char *mnemonic,
121
+ const char *bucket_id,
122
+ const char *file_name,
123
+ char **encrypted_name);
124
+
74
125
  /**
75
126
  * @brief Calculate deterministic key by getting sha512 of key + id
76
127
  *
@@ -1125,9 +1125,7 @@ static void determine_decryption_key_v0(storj_download_state_t *state)
1125
1125
 
1126
1126
  static void determine_decryption_key(storj_download_state_t *state)
1127
1127
  {
1128
- if (!state->env->encrypt_options ||
1129
- !state->env->encrypt_options->mnemonic) {
1130
-
1128
+ if (!state->env->encrypt_options) {
1131
1129
  state->decrypt_key = NULL;
1132
1130
  state->decrypt_ctr = NULL;
1133
1131
  } else {
@@ -1240,6 +1238,7 @@ static void request_info(uv_work_t *work)
1240
1238
  req->info->size = 0;
1241
1239
  req->info->hmac = NULL;
1242
1240
  req->info->id = NULL;
1241
+ req->info->bucket_id = NULL;
1243
1242
  req->info->decrypted = false;
1244
1243
  req->info->index = NULL;
1245
1244
 
@@ -22,42 +22,14 @@ static void create_bucket_request_worker(uv_work_t *work)
22
22
  create_bucket_request_t *req = work->data;
23
23
  int status_code = 0;
24
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) {
25
+ // Encrypt the bucket name
26
+ if (encrypt_bucket_name(req->encrypt_options->mnemonic,
27
+ req->bucket_name,
28
+ (char **)&req->encrypted_bucket_name)) {
33
29
  req->error_code = STORJ_MEMORY_ERROR;
34
30
  return;
35
31
  }
36
32
 
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
33
  struct json_object *body = json_object_new_object();
62
34
  json_object *name = json_object_new_string(req->encrypted_bucket_name);
63
35
  json_object_object_add(body, "name", name);
@@ -72,10 +44,14 @@ static void create_bucket_request_worker(uv_work_t *work)
72
44
  req->bucket = malloc(sizeof(storj_bucket_meta_t));
73
45
 
74
46
  struct json_object *id;
47
+ struct json_object *created;
48
+
75
49
  json_object_object_get_ex(req->response, "id", &id);
50
+ json_object_object_get_ex(req->response, "created", &created);
76
51
 
77
52
  req->bucket->id = json_object_get_string(id);
78
53
  req->bucket->name = req->bucket_name;
54
+ req->bucket->created = json_object_get_string(created);
79
55
  req->bucket->decrypted = true;
80
56
  }
81
57
 
@@ -104,29 +80,6 @@ static void get_buckets_request_worker(uv_work_t *work)
104
80
  req->total_buckets = num_buckets;
105
81
  }
106
82
 
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
83
  struct json_object *bucket_item;
131
84
  struct json_object *name;
132
85
  struct json_object *created;
@@ -154,14 +107,17 @@ static void get_buckets_request_worker(uv_work_t *work)
154
107
  continue;
155
108
  }
156
109
  char *decrypted_name;
157
- int error_status = decrypt_meta(encrypted_name, key,
158
- &decrypted_name);
110
+ int error_status = decrypt_bucket_name(req->encrypt_options->mnemonic,
111
+ encrypted_name,
112
+ &decrypted_name);
159
113
  if (!error_status) {
160
114
  bucket->decrypted = true;
161
115
  bucket->name = decrypted_name;
162
- } else {
116
+ } else if (error_status == STORJ_META_DECRYPTION_ERROR){
163
117
  bucket->decrypted = false;
164
118
  bucket->name = strdup(encrypted_name);
119
+ } else {
120
+ req->error_code = STORJ_MEMORY_ERROR;
165
121
  }
166
122
  }
167
123
  }
@@ -182,29 +138,6 @@ static void get_bucket_request_worker(uv_work_t *work)
182
138
  return;
183
139
  }
184
140
 
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
141
  struct json_object *name;
209
142
  struct json_object *created;
210
143
  struct json_object *id;
@@ -226,18 +159,66 @@ static void get_bucket_request_worker(uv_work_t *work)
226
159
  const char *encrypted_name = json_object_get_string(name);
227
160
  if (encrypted_name) {
228
161
  char *decrypted_name;
229
- int error_status = decrypt_meta(encrypted_name, key,
230
- &decrypted_name);
162
+ int error_status = decrypt_bucket_name(req->encrypt_options->mnemonic,
163
+ encrypted_name,
164
+ &decrypted_name);
231
165
  if (!error_status) {
232
166
  req->bucket->decrypted = true;
233
167
  req->bucket->name = decrypted_name;
234
- } else {
168
+ } else if (error_status == STORJ_META_DECRYPTION_ERROR){
235
169
  req->bucket->decrypted = false;
236
170
  req->bucket->name = strdup(encrypted_name);
171
+ } else {
172
+ req->error_code = STORJ_MEMORY_ERROR;
237
173
  }
238
174
  }
239
175
  }
240
176
 
177
+ static void get_bucket_id_request_worker(uv_work_t *work)
178
+ {
179
+ get_bucket_id_request_t *req = work->data;
180
+ int status_code = 0;
181
+
182
+ // Encrypt the bucket name
183
+ char *encrypted_bucket_name;
184
+ if (encrypt_bucket_name(req->encrypt_options->mnemonic,
185
+ req->bucket_name,
186
+ &encrypted_bucket_name)) {
187
+ req->error_code = STORJ_MEMORY_ERROR;
188
+ goto cleanup;
189
+ }
190
+
191
+ char *escaped_encrypted_bucket_name = str_replace("/", "%2F", encrypted_bucket_name);
192
+ if (!escaped_encrypted_bucket_name) {
193
+ req->error_code = STORJ_MEMORY_ERROR;
194
+ goto cleanup;
195
+ }
196
+
197
+ char *path = str_concat_many(2, "/bucket-ids/", escaped_encrypted_bucket_name);
198
+ if (!path) {
199
+ req->error_code = STORJ_MEMORY_ERROR;
200
+ goto cleanup;
201
+ }
202
+
203
+ req->error_code = fetch_json(req->http_options,
204
+ req->options, "GET", path, NULL,
205
+ true, &req->response, &status_code);
206
+
207
+ if (req->response != NULL) {
208
+ struct json_object *id;
209
+ json_object_object_get_ex(req->response, "id", &id);
210
+ req->bucket_id = json_object_get_string(id);
211
+ }
212
+
213
+ req->status_code = status_code;
214
+
215
+ cleanup:
216
+
217
+ free(encrypted_bucket_name);
218
+ free(escaped_encrypted_bucket_name);
219
+ free(path);
220
+ }
221
+
241
222
  static void list_files_request_worker(uv_work_t *work)
242
223
  {
243
224
  list_files_request_t *req = work->data;
@@ -260,35 +241,18 @@ static void list_files_request_worker(uv_work_t *work)
260
241
  req->total_files = num_files;
261
242
  }
262
243
 
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
244
  struct json_object *file;
287
245
  struct json_object *filename;
288
246
  struct json_object *mimetype;
289
247
  struct json_object *size;
290
248
  struct json_object *id;
249
+ struct json_object *bucket_id;
291
250
  struct json_object *created;
251
+ struct json_object *hmac;
252
+ struct json_object *hmac_value;
253
+ struct json_object *erasure;
254
+ struct json_object *erasure_type;
255
+ struct json_object *index;
292
256
 
293
257
  for (int i = 0; i < num_files; i++) {
294
258
  file = json_object_array_get_idx(req->response, i);
@@ -297,17 +261,24 @@ static void list_files_request_worker(uv_work_t *work)
297
261
  json_object_object_get_ex(file, "mimetype", &mimetype);
298
262
  json_object_object_get_ex(file, "size", &size);
299
263
  json_object_object_get_ex(file, "id", &id);
264
+ json_object_object_get_ex(file, "bucket", &bucket_id);
300
265
  json_object_object_get_ex(file, "created", &created);
266
+ json_object_object_get_ex(file, "hmac", &hmac);
267
+ json_object_object_get_ex(hmac, "value", &hmac_value);
268
+ json_object_object_get_ex(file, "erasure", &erasure);
269
+ json_object_object_get_ex(erasure, "type", &erasure_type);
270
+ json_object_object_get_ex(file, "index", &index);
301
271
 
302
272
  storj_file_meta_t *file = &req->files[i];
303
273
 
304
274
  file->created = json_object_get_string(created);
305
275
  file->mimetype = json_object_get_string(mimetype);
306
276
  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
277
+ file->erasure = json_object_get_string(erasure_type);
278
+ file->index = json_object_get_string(index);
279
+ file->hmac = json_object_get_string(hmac_value);
310
280
  file->id = json_object_get_string(id);
281
+ file->bucket_id = json_object_get_string(bucket_id);
311
282
  file->decrypted = false;
312
283
  file->filename = NULL;
313
284
 
@@ -320,18 +291,138 @@ static void list_files_request_worker(uv_work_t *work)
320
291
  continue;
321
292
  }
322
293
  char *decrypted_file_name;
323
- int error_status = decrypt_meta(encrypted_file_name, key,
324
- &decrypted_file_name);
294
+ int error_status = decrypt_file_name(req->encrypt_options->mnemonic,
295
+ req->bucket_id,
296
+ encrypted_file_name,
297
+ &decrypted_file_name);
325
298
  if (!error_status) {
326
299
  file->decrypted = true;
327
300
  file->filename = decrypted_file_name;
328
- } else {
301
+ } else if (error_status == STORJ_META_DECRYPTION_ERROR) {
329
302
  file->decrypted = false;
330
303
  file->filename = strdup(encrypted_file_name);
304
+ } else {
305
+ req->error_code = STORJ_MEMORY_ERROR;
306
+ }
307
+ }
308
+ }
309
+
310
+ static void get_file_info_request_worker(uv_work_t *work)
311
+ {
312
+ get_file_info_request_t *req = work->data;
313
+ int status_code = 0;
314
+
315
+ req->error_code = fetch_json(req->http_options,
316
+ req->options, req->method, req->path, req->body,
317
+ req->auth, &req->response, &status_code);
318
+
319
+ req->status_code = status_code;
320
+
321
+ struct json_object *filename;
322
+ struct json_object *mimetype;
323
+ struct json_object *size;
324
+ struct json_object *id;
325
+ struct json_object *bucket_id;
326
+ struct json_object *created;
327
+ struct json_object *hmac;
328
+ struct json_object *hmac_value;
329
+ struct json_object *erasure;
330
+ struct json_object *erasure_type;
331
+ struct json_object *index;
332
+
333
+ json_object_object_get_ex(req->response, "filename", &filename);
334
+ json_object_object_get_ex(req->response, "mimetype", &mimetype);
335
+ json_object_object_get_ex(req->response, "size", &size);
336
+ json_object_object_get_ex(req->response, "id", &id);
337
+ json_object_object_get_ex(req->response, "bucket", &bucket_id);
338
+ json_object_object_get_ex(req->response, "created", &created);
339
+ json_object_object_get_ex(req->response, "hmac", &hmac);
340
+ json_object_object_get_ex(hmac, "value", &hmac_value);
341
+ json_object_object_get_ex(req->response, "erasure", &erasure);
342
+ json_object_object_get_ex(erasure, "type", &erasure_type);
343
+ json_object_object_get_ex(req->response, "index", &index);
344
+
345
+ req->file = malloc(sizeof(storj_file_meta_t));
346
+ req->file->created = json_object_get_string(created);
347
+ req->file->mimetype = json_object_get_string(mimetype);
348
+ req->file->size = json_object_get_int64(size);
349
+ req->file->erasure = json_object_get_string(erasure_type);
350
+ req->file->index = json_object_get_string(index);
351
+ req->file->hmac = json_object_get_string(hmac_value);
352
+ req->file->id = json_object_get_string(id);
353
+ req->file->bucket_id = json_object_get_string(bucket_id);
354
+ req->file->decrypted = false;
355
+ req->file->filename = NULL;
356
+
357
+ // Attempt to decrypt the filename, otherwise
358
+ // we will default the filename to the encrypted text.
359
+ // The decrypted flag will be set to indicate the status
360
+ // of decryption for alternative display.
361
+ const char *encrypted_file_name = json_object_get_string(filename);
362
+ if (encrypted_file_name) {
363
+ char *decrypted_file_name;
364
+ int error_status = decrypt_file_name(req->encrypt_options->mnemonic,
365
+ req->bucket_id,
366
+ encrypted_file_name,
367
+ &decrypted_file_name);
368
+ if (!error_status) {
369
+ req->file->decrypted = true;
370
+ req->file->filename = decrypted_file_name;
371
+ } else if (error_status == STORJ_META_DECRYPTION_ERROR) {
372
+ req->file->decrypted = false;
373
+ req->file->filename = strdup(encrypted_file_name);
374
+ } else {
375
+ req->error_code = STORJ_MEMORY_ERROR;
331
376
  }
332
377
  }
333
378
  }
334
379
 
380
+ static void get_file_id_request_worker(uv_work_t *work)
381
+ {
382
+ get_file_id_request_t *req = work->data;
383
+ int status_code = 0;
384
+
385
+ char *encrypted_file_name;
386
+ if (encrypt_file_name(req->encrypt_options->mnemonic,
387
+ req->bucket_id,
388
+ req->file_name,
389
+ &encrypted_file_name)) {
390
+ req->error_code = STORJ_MEMORY_ERROR;
391
+ goto cleanup;
392
+ }
393
+
394
+ char *escaped_encrypted_file_name = str_replace("/", "%2F", encrypted_file_name);
395
+ if (!escaped_encrypted_file_name) {
396
+ req->error_code = STORJ_MEMORY_ERROR;
397
+ goto cleanup;
398
+ }
399
+
400
+ char *path = str_concat_many(4, "/buckets/", req->bucket_id,
401
+ "/file-ids/", escaped_encrypted_file_name);
402
+ if (!path) {
403
+ req->error_code = STORJ_MEMORY_ERROR;
404
+ goto cleanup;
405
+ }
406
+
407
+ req->error_code = fetch_json(req->http_options,
408
+ req->options, "GET", path, NULL,
409
+ true, &req->response, &status_code);
410
+
411
+ if (req->response != NULL) {
412
+ struct json_object *id;
413
+ json_object_object_get_ex(req->response, "id", &id);
414
+ req->file_id = json_object_get_string(id);
415
+ }
416
+
417
+ req->status_code = status_code;
418
+
419
+ cleanup:
420
+
421
+ free(encrypted_file_name);
422
+ free(escaped_encrypted_file_name);
423
+ free(path);
424
+ }
425
+
335
426
  static uv_work_t *uv_work_new()
336
427
  {
337
428
  uv_work_t *work = malloc(sizeof(uv_work_t));
@@ -401,6 +492,39 @@ static list_files_request_t *list_files_request_new(
401
492
  return req;
402
493
  }
403
494
 
495
+ static get_file_info_request_t *get_file_info_request_new(
496
+ storj_http_options_t *http_options,
497
+ storj_bridge_options_t *options,
498
+ storj_encrypt_options_t *encrypt_options,
499
+ const char *bucket_id,
500
+ char *method,
501
+ char *path,
502
+ struct json_object *request_body,
503
+ bool auth,
504
+ void *handle)
505
+ {
506
+ get_file_info_request_t *req = malloc(sizeof(get_file_info_request_t));
507
+ if (!req) {
508
+ return NULL;
509
+ }
510
+
511
+ req->http_options = http_options;
512
+ req->options = options;
513
+ req->encrypt_options = encrypt_options;
514
+ req->bucket_id = bucket_id;
515
+ req->method = method;
516
+ req->path = path;
517
+ req->auth = auth;
518
+ req->body = request_body;
519
+ req->response = NULL;
520
+ req->file = NULL;
521
+ req->error_code = 0;
522
+ req->status_code = 0;
523
+ req->handle = handle;
524
+
525
+ return req;
526
+ }
527
+
404
528
  static create_bucket_request_t *create_bucket_request_new(
405
529
  storj_http_options_t *http_options,
406
530
  storj_bridge_options_t *bridge_options,
@@ -490,6 +614,58 @@ static get_bucket_request_t *get_bucket_request_new(
490
614
  return req;
491
615
  }
492
616
 
617
+ static get_bucket_id_request_t *get_bucket_id_request_new(
618
+ storj_http_options_t *http_options,
619
+ storj_bridge_options_t *options,
620
+ storj_encrypt_options_t *encrypt_options,
621
+ const char *bucket_name,
622
+ void *handle)
623
+ {
624
+ get_bucket_id_request_t *req = malloc(sizeof(get_bucket_id_request_t));
625
+ if (!req) {
626
+ return NULL;
627
+ }
628
+
629
+ req->http_options = http_options;
630
+ req->options = options;
631
+ req->encrypt_options = encrypt_options;
632
+ req->bucket_name = bucket_name;
633
+ req->response = NULL;
634
+ req->bucket_id = NULL;
635
+ req->error_code = 0;
636
+ req->status_code = 0;
637
+ req->handle = handle;
638
+
639
+ return req;
640
+ }
641
+
642
+ static get_file_id_request_t *get_file_id_request_new(
643
+ storj_http_options_t *http_options,
644
+ storj_bridge_options_t *options,
645
+ storj_encrypt_options_t *encrypt_options,
646
+ const char *bucket_id,
647
+ const char *file_name,
648
+ void *handle)
649
+ {
650
+ get_file_id_request_t *req = malloc(sizeof(get_file_id_request_t));
651
+ if (!req) {
652
+ return NULL;
653
+ }
654
+
655
+ req->http_options = http_options;
656
+ req->options = options;
657
+ req->encrypt_options = encrypt_options;
658
+ req->bucket_id = bucket_id;
659
+ req->file_name = file_name;
660
+ req->response = NULL;
661
+ req->file_id = NULL;
662
+ req->error_code = 0;
663
+ req->status_code = 0;
664
+ req->handle = handle;
665
+
666
+ return req;
667
+ }
668
+
493
669
  static uv_work_t *json_request_work_new(
494
670
  storj_env_t *env,
495
671
  char *method,
@@ -1190,7 +1366,9 @@ STORJ_API int storj_bridge_get_buckets(storj_env_t *env, void *handle, uv_after_
1190
1366
 
1191
1367
  STORJ_API void storj_free_get_buckets_request(get_buckets_request_t *req)
1192
1368
  {
1193
- json_object_put(req->response);
1369
+ if (req->response) {
1370
+ json_object_put(req->response);
1371
+ }
1194
1372
  if (req->buckets && req->total_buckets > 0) {
1195
1373
  for (int i = 0; i < req->total_buckets; i++) {
1196
1374
  free((char *)req->buckets[i].name);
@@ -1271,7 +1449,9 @@ STORJ_API int storj_bridge_get_bucket(storj_env_t *env,
1271
1449
 
1272
1450
  STORJ_API void storj_free_get_bucket_request(get_bucket_request_t *req)
1273
1451
  {
1274
- json_object_put(req->response);
1452
+ if (req->response) {
1453
+ json_object_put(req->response);
1454
+ }
1275
1455
  free(req->path);
1276
1456
  if (req->bucket) {
1277
1457
  free((char *)req->bucket->name);
@@ -1280,6 +1460,27 @@ STORJ_API void storj_free_get_bucket_request(get_bucket_request_t *req)
1280
1460
  free(req);
1281
1461
  }
1282
1462
 
1463
+ STORJ_API int storj_bridge_get_bucket_id(storj_env_t *env,
1464
+ const char *name,
1465
+ void *handle,
1466
+ uv_after_work_cb cb)
1467
+ {
1468
+ uv_work_t *work = uv_work_new();
1469
+ if (!work) {
1470
+ return STORJ_MEMORY_ERROR;
1471
+ }
1472
+
1473
+ work->data = get_bucket_id_request_new(env->http_options,
1474
+ env->bridge_options,
1475
+ env->encrypt_options,
1476
+ name, handle);
1477
+ if (!work->data) {
1478
+ return STORJ_MEMORY_ERROR;
1479
+ }
1480
+
1481
+ return uv_queue_work(env->loop, (uv_work_t*) work, get_bucket_id_request_worker, cb);
1482
+ }
1483
+
1283
1484
  STORJ_API int storj_bridge_list_files(storj_env_t *env,
1284
1485
  const char *id,
1285
1486
  void *handle,
@@ -1310,7 +1511,9 @@ STORJ_API int storj_bridge_list_files(storj_env_t *env,
1310
1511
 
1311
1512
  STORJ_API void storj_free_list_files_request(list_files_request_t *req)
1312
1513
  {
1313
- json_object_put(req->response);
1514
+ if (req->response) {
1515
+ json_object_put(req->response);
1516
+ }
1314
1517
  free(req->path);
1315
1518
  if (req->files && req->total_files > 0) {
1316
1519
  for (int i = 0; i < req->total_files; i++) {
@@ -1452,10 +1655,10 @@ STORJ_API int storj_bridge_delete_frame(storj_env_t *env,
1452
1655
  }
1453
1656
 
1454
1657
  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)
1658
+ const char *bucket_id,
1659
+ const char *file_id,
1660
+ void *handle,
1661
+ uv_after_work_cb cb)
1459
1662
  {
1460
1663
  char *path = str_concat_many(5, "/buckets/", bucket_id, "/files/",
1461
1664
  file_id, "/info");
@@ -1463,13 +1666,58 @@ STORJ_API int storj_bridge_get_file_info(storj_env_t *env,
1463
1666
  return STORJ_MEMORY_ERROR;
1464
1667
  }
1465
1668
 
1466
- uv_work_t *work = json_request_work_new(env, "GET", path, NULL,
1467
- true, handle);
1669
+ uv_work_t *work = uv_work_new();
1468
1670
  if (!work) {
1469
1671
  return STORJ_MEMORY_ERROR;
1470
1672
  }
1471
1673
 
1472
- return uv_queue_work(env->loop, (uv_work_t*) work, json_request_worker, cb);
1674
+ work->data = get_file_info_request_new(env->http_options,
1675
+ env->bridge_options,
1676
+ env->encrypt_options,
1677
+ bucket_id, "GET", path,
1678
+ NULL, true, handle);
1679
+
1680
+ if (!work->data) {
1681
+ return STORJ_MEMORY_ERROR;
1682
+ }
1683
+
1684
+ return uv_queue_work(env->loop, (uv_work_t*) work,
1685
+ get_file_info_request_worker, cb);
1686
+ }
1687
+
1688
+ STORJ_API int storj_bridge_get_file_id(storj_env_t *env,
1689
+ const char *bucket_id,
1690
+ const char *file_name,
1691
+ void *handle,
1692
+ uv_after_work_cb cb)
1693
+ {
1694
+ uv_work_t *work = uv_work_new();
1695
+ if (!work) {
1696
+ return STORJ_MEMORY_ERROR;
1697
+ }
1698
+
1699
+ work->data = get_file_id_request_new(env->http_options,
1700
+ env->bridge_options,
1701
+ env->encrypt_options,
1702
+ bucket_id, file_name, handle);
1703
+ if (!work->data) {
1704
+ return STORJ_MEMORY_ERROR;
1705
+ }
1706
+
1707
+ return uv_queue_work(env->loop, (uv_work_t*) work, get_file_id_request_worker, cb);
1708
+ }
1709
+
1710
+ STORJ_API void storj_free_get_file_info_request(get_file_info_request_t *req)
1711
+ {
1712
+ if (req->response) {
1713
+ json_object_put(req->response);
1714
+ }
1715
+ free(req->path);
1716
+ if (req->file) {
1717
+ free((char *)req->file->filename);
1718
+ }
1719
+ free(req->file);
1720
+ free(req);
1473
1721
  }
1474
1722
 
1475
1723
  STORJ_API int storj_bridge_list_mirrors(storj_env_t *env,