ruby-libstorj 0.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +111 -0
- data/Guardfile +21 -0
- data/LICENSE +502 -0
- data/README.md +262 -0
- data/Rakefile +76 -0
- data/ext/libstorj/.gitignore +47 -0
- data/ext/libstorj/.travis.yml +27 -0
- data/ext/libstorj/Doxyfile +2427 -0
- data/ext/libstorj/LICENSE +502 -0
- data/ext/libstorj/Makefile.am +6 -0
- data/ext/libstorj/README.md +198 -0
- data/ext/libstorj/autogen.sh +3 -0
- data/ext/libstorj/configure.ac +64 -0
- data/ext/libstorj/depends/Makefile +153 -0
- data/ext/libstorj/depends/config.guess +1462 -0
- data/ext/libstorj/depends/config.sub +1823 -0
- data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
- data/ext/libstorj/depends/packages/cctools.mk +7 -0
- data/ext/libstorj/depends/packages/clang.mk +7 -0
- data/ext/libstorj/depends/packages/gmp.mk +23 -0
- data/ext/libstorj/depends/packages/gnutls.mk +25 -0
- data/ext/libstorj/depends/packages/json-c.mk +7 -0
- data/ext/libstorj/depends/packages/libcurl.mk +39 -0
- data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
- data/ext/libstorj/depends/packages/libuv.mk +7 -0
- data/ext/libstorj/depends/packages/nettle.mk +30 -0
- data/ext/libstorj/libstorj.pc.in +11 -0
- data/ext/libstorj/src/Makefile.am +23 -0
- data/ext/libstorj/src/bip39.c +233 -0
- data/ext/libstorj/src/bip39.h +64 -0
- data/ext/libstorj/src/bip39_english.h +2074 -0
- data/ext/libstorj/src/cli.c +1494 -0
- data/ext/libstorj/src/crypto.c +525 -0
- data/ext/libstorj/src/crypto.h +178 -0
- data/ext/libstorj/src/downloader.c +1923 -0
- data/ext/libstorj/src/downloader.h +163 -0
- data/ext/libstorj/src/http.c +688 -0
- data/ext/libstorj/src/http.h +175 -0
- data/ext/libstorj/src/rs.c +962 -0
- data/ext/libstorj/src/rs.h +99 -0
- data/ext/libstorj/src/storj.c +1523 -0
- data/ext/libstorj/src/storj.h +1014 -0
- data/ext/libstorj/src/uploader.c +2736 -0
- data/ext/libstorj/src/uploader.h +181 -0
- data/ext/libstorj/src/utils.c +336 -0
- data/ext/libstorj/src/utils.h +65 -0
- data/ext/libstorj/test/Makefile.am +27 -0
- data/ext/libstorj/test/mockbridge.c +260 -0
- data/ext/libstorj/test/mockbridge.json +687 -0
- data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
- data/ext/libstorj/test/mockfarmer.c +358 -0
- data/ext/libstorj/test/storjtests.h +41 -0
- data/ext/libstorj/test/tests.c +1617 -0
- data/ext/libstorj/test/tests_rs.c +869 -0
- data/ext/ruby-libstorj/extconf.rb +8 -0
- data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
- data/lib/ruby-libstorj.rb +1 -0
- data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
- data/lib/ruby-libstorj/env.rb +178 -0
- data/lib/ruby-libstorj/ext/bucket.rb +71 -0
- data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
- data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
- data/lib/ruby-libstorj/ext/ext.rb +71 -0
- data/lib/ruby-libstorj/ext/file.rb +84 -0
- data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
- data/lib/ruby-libstorj/ext/json_request.rb +51 -0
- data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
- data/lib/ruby-libstorj/ext/types.rb +226 -0
- data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
- data/lib/ruby-libstorj/libstorj.rb +22 -0
- data/lib/ruby-libstorj/mixins/storj.rb +27 -0
- data/lib/ruby-libstorj/struct.rb +42 -0
- data/ruby-libstorj.gemspec +57 -0
- data/spec/helpers/options.yml.example +22 -0
- data/spec/helpers/shared_rake_examples.rb +132 -0
- data/spec/helpers/storj_options.rb +96 -0
- data/spec/helpers/upload.data +3 -0
- data/spec/helpers/upload.data.sha256 +1 -0
- data/spec/libstorj_spec.rb +0 -0
- data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
- data/spec/ruby-libstorj/env_spec.rb +353 -0
- data/spec/ruby-libstorj/ext_spec.rb +75 -0
- data/spec/ruby-libstorj/json_request_spec.rb +13 -0
- data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
- data/spec/ruby-libstorj/struct_spec.rb +64 -0
- data/spec/spec_helper.rb +113 -0
- 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
|
+
}
|