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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +111 -0
  7. data/Guardfile +21 -0
  8. data/LICENSE +502 -0
  9. data/README.md +262 -0
  10. data/Rakefile +76 -0
  11. data/ext/libstorj/.gitignore +47 -0
  12. data/ext/libstorj/.travis.yml +27 -0
  13. data/ext/libstorj/Doxyfile +2427 -0
  14. data/ext/libstorj/LICENSE +502 -0
  15. data/ext/libstorj/Makefile.am +6 -0
  16. data/ext/libstorj/README.md +198 -0
  17. data/ext/libstorj/autogen.sh +3 -0
  18. data/ext/libstorj/configure.ac +64 -0
  19. data/ext/libstorj/depends/Makefile +153 -0
  20. data/ext/libstorj/depends/config.guess +1462 -0
  21. data/ext/libstorj/depends/config.sub +1823 -0
  22. data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
  23. data/ext/libstorj/depends/packages/cctools.mk +7 -0
  24. data/ext/libstorj/depends/packages/clang.mk +7 -0
  25. data/ext/libstorj/depends/packages/gmp.mk +23 -0
  26. data/ext/libstorj/depends/packages/gnutls.mk +25 -0
  27. data/ext/libstorj/depends/packages/json-c.mk +7 -0
  28. data/ext/libstorj/depends/packages/libcurl.mk +39 -0
  29. data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
  30. data/ext/libstorj/depends/packages/libuv.mk +7 -0
  31. data/ext/libstorj/depends/packages/nettle.mk +30 -0
  32. data/ext/libstorj/libstorj.pc.in +11 -0
  33. data/ext/libstorj/src/Makefile.am +23 -0
  34. data/ext/libstorj/src/bip39.c +233 -0
  35. data/ext/libstorj/src/bip39.h +64 -0
  36. data/ext/libstorj/src/bip39_english.h +2074 -0
  37. data/ext/libstorj/src/cli.c +1494 -0
  38. data/ext/libstorj/src/crypto.c +525 -0
  39. data/ext/libstorj/src/crypto.h +178 -0
  40. data/ext/libstorj/src/downloader.c +1923 -0
  41. data/ext/libstorj/src/downloader.h +163 -0
  42. data/ext/libstorj/src/http.c +688 -0
  43. data/ext/libstorj/src/http.h +175 -0
  44. data/ext/libstorj/src/rs.c +962 -0
  45. data/ext/libstorj/src/rs.h +99 -0
  46. data/ext/libstorj/src/storj.c +1523 -0
  47. data/ext/libstorj/src/storj.h +1014 -0
  48. data/ext/libstorj/src/uploader.c +2736 -0
  49. data/ext/libstorj/src/uploader.h +181 -0
  50. data/ext/libstorj/src/utils.c +336 -0
  51. data/ext/libstorj/src/utils.h +65 -0
  52. data/ext/libstorj/test/Makefile.am +27 -0
  53. data/ext/libstorj/test/mockbridge.c +260 -0
  54. data/ext/libstorj/test/mockbridge.json +687 -0
  55. data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
  56. data/ext/libstorj/test/mockfarmer.c +358 -0
  57. data/ext/libstorj/test/storjtests.h +41 -0
  58. data/ext/libstorj/test/tests.c +1617 -0
  59. data/ext/libstorj/test/tests_rs.c +869 -0
  60. data/ext/ruby-libstorj/extconf.rb +8 -0
  61. data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
  62. data/lib/ruby-libstorj.rb +1 -0
  63. data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
  64. data/lib/ruby-libstorj/env.rb +178 -0
  65. data/lib/ruby-libstorj/ext/bucket.rb +71 -0
  66. data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
  67. data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
  68. data/lib/ruby-libstorj/ext/ext.rb +71 -0
  69. data/lib/ruby-libstorj/ext/file.rb +84 -0
  70. data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
  71. data/lib/ruby-libstorj/ext/json_request.rb +51 -0
  72. data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
  73. data/lib/ruby-libstorj/ext/types.rb +226 -0
  74. data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
  75. data/lib/ruby-libstorj/libstorj.rb +22 -0
  76. data/lib/ruby-libstorj/mixins/storj.rb +27 -0
  77. data/lib/ruby-libstorj/struct.rb +42 -0
  78. data/ruby-libstorj.gemspec +57 -0
  79. data/spec/helpers/options.yml.example +22 -0
  80. data/spec/helpers/shared_rake_examples.rb +132 -0
  81. data/spec/helpers/storj_options.rb +96 -0
  82. data/spec/helpers/upload.data +3 -0
  83. data/spec/helpers/upload.data.sha256 +1 -0
  84. data/spec/libstorj_spec.rb +0 -0
  85. data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
  86. data/spec/ruby-libstorj/env_spec.rb +353 -0
  87. data/spec/ruby-libstorj/ext_spec.rb +75 -0
  88. data/spec/ruby-libstorj/json_request_spec.rb +13 -0
  89. data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
  90. data/spec/ruby-libstorj/struct_spec.rb +64 -0
  91. data/spec/spec_helper.rb +113 -0
  92. metadata +136 -0
@@ -0,0 +1,1494 @@
1
+ #include <errno.h>
2
+ #include <getopt.h>
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+ #include <sys/stat.h>
7
+
8
+ #ifdef _WIN32
9
+ #include <winsock2.h>
10
+ #include <windows.h>
11
+ #include <direct.h>
12
+ #else
13
+ #include <termios.h>
14
+ #include <unistd.h>
15
+ #endif
16
+
17
+ #include "storj.h"
18
+
19
+ #define STORJ_THREADPOOL_SIZE "64"
20
+
21
+ typedef struct {
22
+ char *user;
23
+ char *pass;
24
+ char *host;
25
+ char *mnemonic;
26
+ char *key;
27
+ } user_options_t;
28
+
29
+ #ifndef errno
30
+ extern int errno;
31
+ #endif
32
+
33
+ static inline void noop() {};
34
+
35
+ #define HELP_TEXT "usage: storj [<options>] <command> [<args>]\n\n" \
36
+ "These are common Storj commands for various situations:\n\n" \
37
+ "setting up users profiles\n" \
38
+ " register setup a new storj bridge user\n" \
39
+ " import-keys import existing user\n" \
40
+ " export-keys export bridge user, password and " \
41
+ "encryption keys\n\n" \
42
+ "working with buckets and files\n" \
43
+ " list-buckets\n" \
44
+ " list-files <bucket-id>\n" \
45
+ " remove-file <bucket-id> <file-id>\n" \
46
+ " add-bucket <name> \n" \
47
+ " remove-bucket <bucket-id>\n" \
48
+ " list-mirrors <bucket-id> <file-id>\n\n" \
49
+ "downloading and uploading files\n" \
50
+ " upload-file <bucket-id> <path>\n" \
51
+ " download-file <bucket-id> <file-id> <path>\n" \
52
+ "bridge api information\n" \
53
+ " get-info\n\n" \
54
+ "options:\n" \
55
+ " -h, --help output usage information\n" \
56
+ " -v, --version output the version number\n" \
57
+ " -u, --url <url> set the base url for the api\n" \
58
+ " -p, --proxy <url> set the socks proxy " \
59
+ "(e.g. <[protocol://][user:password@]proxyhost[:port]>)\n" \
60
+ " -l, --log <level> set the log level (default 0)\n" \
61
+ " -d, --debug set the debug log level\n\n" \
62
+ "environment variables:\n" \
63
+ " STORJ_KEYPASS imported user settings passphrase\n" \
64
+ " STORJ_BRIDGE the bridge host " \
65
+ "(e.g. https://api.storj.io)\n" \
66
+ " STORJ_BRIDGE_USER bridge username\n" \
67
+ " STORJ_BRIDGE_PASS bridge password\n" \
68
+ " STORJ_ENCRYPTION_KEY file encryption key\n\n"
69
+
70
+
71
+ #define CLI_VERSION "libstorj-2.0.0-beta"
72
+
73
+ static void json_logger(const char *message, int level, void *handle)
74
+ {
75
+ printf("{\"message\": \"%s\", \"level\": %i, \"timestamp\": %" PRIu64 "}\n",
76
+ message, level, storj_util_timestamp());
77
+ }
78
+
79
+ static char *get_home_dir()
80
+ {
81
+ #ifdef _WIN32
82
+ return getenv("USERPROFILE");
83
+ #else
84
+ return getenv("HOME");
85
+ #endif
86
+ }
87
+
88
+ static int make_user_directory(char *path)
89
+ {
90
+ struct stat st = {0};
91
+ if (stat(path, &st) == -1) {
92
+ #if _WIN32
93
+ int mkdir_status = _mkdir(path);
94
+ if (mkdir_status) {
95
+ printf("Unable to create directory %s: code: %i.\n",
96
+ path,
97
+ mkdir_status);
98
+ return 1;
99
+ }
100
+ #else
101
+ if (mkdir(path, 0700)) {
102
+ printf("Unable to create directory %s: reason: %s\n",
103
+ path,
104
+ strerror(errno));
105
+ return 1;
106
+ }
107
+ #endif
108
+ }
109
+ return 0;
110
+ }
111
+
112
+ static const char *get_filename_separator(const char *file_path)
113
+ {
114
+ const char *file_name = NULL;
115
+ #ifdef _WIN32
116
+ file_name = strrchr(file_path, '\\');
117
+ if (!file_name) {
118
+ file_name = strrchr(file_path, '/');
119
+ }
120
+ if (!file_name && file_path) {
121
+ file_name = file_path;
122
+ }
123
+ if (!file_name) {
124
+ return NULL;
125
+ }
126
+ if (file_name[0] == '\\' || file_name[0] == '/') {
127
+ file_name++;
128
+ }
129
+ #else
130
+ file_name = strrchr(file_path, '/');
131
+ if (!file_name && file_path) {
132
+ file_name = file_path;
133
+ }
134
+ if (!file_name) {
135
+ return NULL;
136
+ }
137
+ if (file_name[0] == '/') {
138
+ file_name++;
139
+ }
140
+ #endif
141
+ return file_name;
142
+ }
143
+
144
+ static int get_user_auth_location(char *host, char **root_dir, char **user_file)
145
+ {
146
+ char *home_dir = get_home_dir();
147
+ if (home_dir == NULL) {
148
+ return 1;
149
+ }
150
+
151
+ int len = strlen(home_dir) + strlen("/.storj/");
152
+ *root_dir = calloc(len + 1, sizeof(char));
153
+ if (!*root_dir) {
154
+ return 1;
155
+ }
156
+
157
+ strcpy(*root_dir, home_dir);
158
+ strcat(*root_dir, "/.storj/");
159
+
160
+ len = strlen(*root_dir) + strlen(host) + strlen(".json");
161
+ *user_file = calloc(len + 1, sizeof(char));
162
+ if (!*user_file) {
163
+ return 1;
164
+ }
165
+
166
+ strcpy(*user_file, *root_dir);
167
+ strcat(*user_file, host);
168
+ strcat(*user_file, ".json");
169
+
170
+ return 0;
171
+ }
172
+
173
+ static void get_input(char *line)
174
+ {
175
+ if (fgets(line, BUFSIZ, stdin) == NULL) {
176
+ line[0] = '\0';
177
+ } else {
178
+ int len = strlen(line);
179
+ if (len > 0) {
180
+ char *last = strrchr(line, '\n');
181
+ if (last) {
182
+ last[0] = '\0';
183
+ }
184
+ last = strrchr(line, '\r');
185
+ if (last) {
186
+ last[0] = '\0';
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ static int generate_mnemonic(char **mnemonic)
193
+ {
194
+ char *strength_str = NULL;
195
+ int strength = 0;
196
+ int status = 0;
197
+
198
+ printf("We now need to create an secret key used for encrypting " \
199
+ "files.\nPlease choose strength from: 128, 160, 192, 224, 256\n\n");
200
+
201
+ while (strength % 32 || strength < 128 || strength > 256) {
202
+ strength_str = calloc(BUFSIZ, sizeof(char));
203
+ printf("Strength: ");
204
+ get_input(strength_str);
205
+
206
+ if (strength_str != NULL) {
207
+ strength = atoi(strength_str);
208
+ }
209
+
210
+ free(strength_str);
211
+ }
212
+
213
+ if (*mnemonic) {
214
+ free(*mnemonic);
215
+ }
216
+
217
+ *mnemonic = NULL;
218
+
219
+ int generate_code = storj_mnemonic_generate(strength, mnemonic);
220
+ if (*mnemonic == NULL || generate_code == 0) {
221
+ printf("Failed to generate encryption key.\n");
222
+ status = 1;
223
+ status = generate_mnemonic(mnemonic);
224
+ }
225
+
226
+ return status;
227
+ }
228
+
229
+ static int get_password(char *password, int mask)
230
+ {
231
+ int max_pass_len = 512;
232
+
233
+ #ifdef _WIN32
234
+ HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
235
+ DWORD mode = 0;
236
+ DWORD prev_mode = 0;
237
+ GetConsoleMode(hstdin, &mode);
238
+ GetConsoleMode(hstdin, &prev_mode);
239
+ SetConsoleMode(hstdin, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
240
+ #else
241
+ static struct termios prev_terminal;
242
+ static struct termios terminal;
243
+
244
+ tcgetattr(STDIN_FILENO, &prev_terminal);
245
+
246
+ memcpy (&terminal, &prev_terminal, sizeof(struct termios));
247
+ terminal.c_lflag &= ~(ICANON | ECHO);
248
+ terminal.c_cc[VTIME] = 0;
249
+ terminal.c_cc[VMIN] = 1;
250
+ tcsetattr(STDIN_FILENO, TCSANOW, &terminal);
251
+ #endif
252
+
253
+ size_t idx = 0; /* index, number of chars in read */
254
+ int c = 0;
255
+
256
+ const char BACKSPACE = 8;
257
+ const char RETURN = 13;
258
+
259
+ /* read chars from fp, mask if valid char specified */
260
+ #ifdef _WIN32
261
+ long unsigned int char_read = 0;
262
+ while ((ReadConsole(hstdin, &c, 1, &char_read, NULL) && c != '\n' && c != RETURN && c != EOF && idx < max_pass_len - 1) ||
263
+ (idx == max_pass_len - 1 && c == BACKSPACE))
264
+ #else
265
+ while (((c = fgetc(stdin)) != '\n' && c != EOF && idx < max_pass_len - 1) ||
266
+ (idx == max_pass_len - 1 && c == 127))
267
+ #endif
268
+ {
269
+ if (c != 127 && c != BACKSPACE) {
270
+ if (31 < mask && mask < 127) /* valid ascii char */
271
+ fputc(mask, stdout);
272
+ password[idx++] = c;
273
+ } else if (idx > 0) { /* handle backspace (del) */
274
+ if (31 < mask && mask < 127) {
275
+ fputc(0x8, stdout);
276
+ fputc(' ', stdout);
277
+ fputc(0x8, stdout);
278
+ }
279
+ password[--idx] = 0;
280
+ }
281
+ }
282
+ password[idx] = 0; /* null-terminate */
283
+
284
+ // go back to the previous settings
285
+ #ifdef _WIN32
286
+ SetConsoleMode(hstdin, prev_mode);
287
+ #else
288
+ tcsetattr(STDIN_FILENO, TCSANOW, &prev_terminal);
289
+ #endif
290
+
291
+ return idx; /* number of chars in passwd */
292
+ }
293
+
294
+ static int get_password_verify(char *prompt, char *password, int count)
295
+ {
296
+ printf("%s", prompt);
297
+ char first_password[BUFSIZ];
298
+ get_password(first_password, '*');
299
+
300
+ printf("\nAgain to verify: ");
301
+ char second_password[BUFSIZ];
302
+ get_password(second_password, '*');
303
+
304
+ int match = strcmp(first_password, second_password);
305
+ strncpy(password, first_password, BUFSIZ);
306
+
307
+ if (match == 0) {
308
+ return 0;
309
+ } else {
310
+ printf("\nPassphrases did not match. ");
311
+ count++;
312
+ if (count > 3) {
313
+ printf("\n");
314
+ return 1;
315
+ }
316
+ printf("Try again...\n");
317
+ return get_password_verify(prompt, password, count);
318
+ }
319
+ }
320
+
321
+ void close_signal(uv_handle_t *handle)
322
+ {
323
+ ((void)0);
324
+ }
325
+
326
+ static void file_progress(double progress,
327
+ uint64_t downloaded_bytes,
328
+ uint64_t total_bytes,
329
+ void *handle)
330
+ {
331
+ int bar_width = 70;
332
+
333
+ if (progress == 0 && downloaded_bytes == 0) {
334
+ printf("Preparing File...");
335
+ fflush(stdout);
336
+ return;
337
+ }
338
+
339
+ printf("\r[");
340
+ int pos = bar_width * progress;
341
+ for (int i = 0; i < bar_width; ++i) {
342
+ if (i < pos) {
343
+ printf("=");
344
+ } else if (i == pos) {
345
+ printf(">");
346
+ } else {
347
+ printf(" ");
348
+ }
349
+ }
350
+ printf("] %.*f%%", 2, progress * 100);
351
+
352
+ fflush(stdout);
353
+ }
354
+
355
+ static void upload_file_complete(int status, char *file_id, void *handle)
356
+ {
357
+ printf("\n");
358
+ if (status != 0) {
359
+ printf("Upload failure: %s\n", storj_strerror(status));
360
+ exit(status);
361
+ }
362
+
363
+ printf("Upload Success! File ID: %s\n", file_id);
364
+
365
+ free(file_id);
366
+
367
+ exit(0);
368
+ }
369
+
370
+ void upload_signal_handler(uv_signal_t *req, int signum)
371
+ {
372
+ storj_upload_state_t *state = req->data;
373
+ storj_bridge_store_file_cancel(state);
374
+ if (uv_signal_stop(req)) {
375
+ printf("Unable to stop signal\n");
376
+ }
377
+ uv_close((uv_handle_t *)req, close_signal);
378
+ }
379
+
380
+ static int upload_file(storj_env_t *env, char *bucket_id, const char *file_path)
381
+ {
382
+ bool using_stdin = false;
383
+ FILE *fd = fopen(file_path, "r");
384
+
385
+ if (!fd) {
386
+ printf("Invalid file path: %s\n", file_path);
387
+ fd = fdopen(0, "r");
388
+ using_stdin = true;
389
+ }
390
+
391
+ const char *file_name = get_filename_separator(file_path);
392
+
393
+ if (!file_name) {
394
+ file_name = file_path;
395
+ }
396
+
397
+ // Upload opts env variables:
398
+ char *prepare_frame_limit;
399
+ char *push_frame_limit;
400
+ char *push_shard_limit;
401
+ char *rs = getenv("STORJ_REED_SOLOMON");
402
+
403
+ storj_upload_opts_t upload_opts = {
404
+ .prepare_frame_limit = (prepare_frame_limit) ? atoi(prepare_frame_limit) : 1,
405
+ .push_frame_limit = (push_frame_limit) ? atoi(push_frame_limit) : 64,
406
+ .push_shard_limit = (push_shard_limit) ? atoi(push_shard_limit) : 64,
407
+ .rs = (!rs) ? true : (strcmp(rs, "false") == 0) ? false : true,
408
+ .bucket_id = bucket_id,
409
+ .file_name = file_name,
410
+ .fd = fd
411
+ };
412
+
413
+ uv_signal_t *sig = malloc(sizeof(uv_signal_t));
414
+ if (!sig) {
415
+ return 1;
416
+ }
417
+ uv_signal_init(env->loop, sig);
418
+ uv_signal_start(sig, upload_signal_handler, SIGINT);
419
+
420
+
421
+
422
+ storj_progress_cb progress_cb = (storj_progress_cb)noop;
423
+ if (env->log_options->level == 0) {
424
+ progress_cb = file_progress;
425
+ }
426
+
427
+ storj_upload_state_t *state = storj_bridge_store_file(env,
428
+ &upload_opts,
429
+ NULL,
430
+ progress_cb,
431
+ upload_file_complete);
432
+
433
+ if (!state) {
434
+ return 1;
435
+ }
436
+
437
+ sig->data = state;
438
+
439
+ return state->error_status;
440
+ }
441
+
442
+ static void download_file_complete(int status, FILE *fd, void *handle)
443
+ {
444
+ printf("\n");
445
+ fclose(fd);
446
+ if (status) {
447
+ // TODO send to stderr
448
+ switch(status) {
449
+ case STORJ_FILE_DECRYPTION_ERROR:
450
+ printf("Unable to properly decrypt file, please check " \
451
+ "that the correct encryption key was " \
452
+ "imported correctly.\n\n");
453
+ break;
454
+ default:
455
+ printf("Download failure: %s\n", storj_strerror(status));
456
+ }
457
+
458
+ exit(status);
459
+ }
460
+ printf("Download Success!\n");
461
+ exit(0);
462
+ }
463
+
464
+ void download_signal_handler(uv_signal_t *req, int signum)
465
+ {
466
+ storj_download_state_t *state = req->data;
467
+ storj_bridge_resolve_file_cancel(state);
468
+ if (uv_signal_stop(req)) {
469
+ printf("Unable to stop signal\n");
470
+ }
471
+ uv_close((uv_handle_t *)req, close_signal);
472
+ }
473
+
474
+ static int download_file(storj_env_t *env, char *bucket_id,
475
+ char *file_id, char *path)
476
+ {
477
+ FILE *fd = NULL;
478
+
479
+ if (path) {
480
+ char user_input[BUFSIZ];
481
+ memset(user_input, '\0', BUFSIZ);
482
+
483
+ if(access(path, F_OK) != -1 ) {
484
+ printf("Warning: File already exists at path [%s].\n", path);
485
+ while (strcmp(user_input, "y") != 0 && strcmp(user_input, "n") != 0)
486
+ {
487
+ memset(user_input, '\0', BUFSIZ);
488
+ printf("Would you like to overwrite [%s]: [y/n] ", path);
489
+ get_input(user_input);
490
+ }
491
+
492
+ if (strcmp(user_input, "n") == 0) {
493
+ printf("\nCanceled overwriting of [%s].\n", path);
494
+ return 1;
495
+ }
496
+
497
+ unlink(path);
498
+ }
499
+
500
+ fd = fopen(path, "w+");
501
+ } else {
502
+ fd = stdout;
503
+ }
504
+
505
+ if (fd == NULL) {
506
+ // TODO send to stderr
507
+ printf("Unable to open %s: %s\n", path, strerror(errno));
508
+ return 1;
509
+ }
510
+
511
+ uv_signal_t *sig = malloc(sizeof(uv_signal_t));
512
+ uv_signal_init(env->loop, sig);
513
+ uv_signal_start(sig, download_signal_handler, SIGINT);
514
+
515
+ storj_progress_cb progress_cb = (storj_progress_cb)noop;
516
+ if (path && env->log_options->level == 0) {
517
+ progress_cb = file_progress;
518
+ }
519
+
520
+ storj_download_state_t *state = storj_bridge_resolve_file(env, bucket_id,
521
+ file_id, fd, NULL,
522
+ progress_cb,
523
+ download_file_complete);
524
+ if (!state) {
525
+ return 1;
526
+ }
527
+ sig->data = state;
528
+
529
+ return state->error_status;
530
+ }
531
+
532
+ static void list_mirrors_callback(uv_work_t *work_req, int status)
533
+ {
534
+ assert(status == 0);
535
+ json_request_t *req = work_req->data;
536
+
537
+ if (req->status_code != 200) {
538
+ printf("Request failed with status code: %i\n",
539
+ req->status_code);
540
+ }
541
+
542
+ if (req->response == NULL) {
543
+ free(req);
544
+ free(work_req);
545
+ printf("Failed to list mirrors.\n");
546
+ exit(1);
547
+ }
548
+
549
+ int num_mirrors = json_object_array_length(req->response);
550
+
551
+ struct json_object *shard;
552
+ struct json_object *established;
553
+ struct json_object *available;
554
+ struct json_object *item;
555
+ struct json_object *hash;
556
+ struct json_object *contract;
557
+ struct json_object *address;
558
+ struct json_object *port;
559
+ struct json_object *node_id;
560
+
561
+ for (int i = 0; i < num_mirrors; i++) {
562
+ shard = json_object_array_get_idx(req->response, i);
563
+ json_object_object_get_ex(shard, "established",
564
+ &established);
565
+ int num_established =
566
+ json_object_array_length(established);
567
+ for (int j = 0; j < num_established; j++) {
568
+ item = json_object_array_get_idx(established, j);
569
+ if (j == 0) {
570
+ json_object_object_get_ex(item, "shardHash",
571
+ &hash);
572
+ printf("Shard %i: %s\n", i, json_object_get_string(hash));
573
+ }
574
+ json_object_object_get_ex(item, "contract", &contract);
575
+ json_object_object_get_ex(contract, "farmer_id", &node_id);
576
+
577
+ const char *node_id_str = json_object_get_string(node_id);
578
+ printf("\tnodeID: %s\n", node_id_str);
579
+ }
580
+ printf("\n\n");
581
+ }
582
+
583
+ json_object_put(req->response);
584
+ free(req->path);
585
+ free(req);
586
+ free(work_req);
587
+ }
588
+
589
+ static int import_keys(user_options_t *options)
590
+ {
591
+ int status = 0;
592
+ char *host = options->host ? strdup(options->host) : NULL;
593
+ char *user = options->user ? strdup(options->user) : NULL;
594
+ char *pass = options->pass ? strdup(options->pass) : NULL;
595
+ char *key = options->key ? strdup(options->key) : NULL;
596
+ char *mnemonic = options->mnemonic ? strdup(options->mnemonic): NULL;
597
+ char *mnemonic_input = NULL;
598
+ char *user_file = NULL;
599
+ char *root_dir = NULL;
600
+ int num_chars;
601
+
602
+ char *user_input = calloc(BUFSIZ, sizeof(char));
603
+ if (user_input == NULL) {
604
+ printf("Unable to allocate buffer\n");
605
+ status = 1;
606
+ goto clear_variables;
607
+ }
608
+
609
+ if (get_user_auth_location(host, &root_dir, &user_file)) {
610
+ printf("Unable to determine user auth filepath.\n");
611
+ status = 1;
612
+ goto clear_variables;
613
+ }
614
+
615
+ struct stat st;
616
+ if (stat(user_file, &st) == 0) {
617
+ printf("Would you like to overwrite the current settings?: [y/n] ");
618
+ get_input(user_input);
619
+ while (strcmp(user_input, "y") != 0 && strcmp(user_input, "n") != 0)
620
+ {
621
+ printf("Would you like to overwrite the current settings?: [y/n] ");
622
+ get_input(user_input);
623
+ }
624
+
625
+ if (strcmp(user_input, "n") == 0) {
626
+ printf("\nCanceled overwriting of stored credentials.\n");
627
+ status = 1;
628
+ goto clear_variables;
629
+ }
630
+ }
631
+
632
+ if (!user) {
633
+ printf("Bridge username (email): ");
634
+ get_input(user_input);
635
+ num_chars = strlen(user_input);
636
+ user = calloc(num_chars + 1, sizeof(char));
637
+ if (!user) {
638
+ status = 1;
639
+ goto clear_variables;
640
+ }
641
+ memcpy(user, user_input, num_chars * sizeof(char));
642
+ }
643
+
644
+ if (!pass) {
645
+ printf("Bridge password: ");
646
+ pass = calloc(BUFSIZ, sizeof(char));
647
+ if (!pass) {
648
+ status = 1;
649
+ goto clear_variables;
650
+ }
651
+ get_password(pass, '*');
652
+ printf("\n");
653
+ }
654
+
655
+ if (!mnemonic) {
656
+ mnemonic_input = calloc(BUFSIZ, sizeof(char));
657
+ if (!mnemonic_input) {
658
+ status = 1;
659
+ goto clear_variables;
660
+ }
661
+
662
+ printf("\nIf you've previously uploaded files, please enter your" \
663
+ " existing encryption key (12 to 24 words). \nOtherwise leave" \
664
+ " the field blank to generate a new key.\n\n");
665
+
666
+ printf("Encryption key: ");
667
+ get_input(mnemonic_input);
668
+ num_chars = strlen(mnemonic_input);
669
+
670
+ if (num_chars == 0) {
671
+ printf("\n");
672
+ generate_mnemonic(&mnemonic);
673
+ printf("\n");
674
+
675
+ printf("Encryption key: %s\n", mnemonic);
676
+ printf("\n");
677
+ printf("Please make sure to backup this key in a safe location. " \
678
+ "If the key is lost, the data uploaded will also be lost.\n\n");
679
+ } else {
680
+ mnemonic = calloc(num_chars + 1, sizeof(char));
681
+ if (!mnemonic) {
682
+ status = 1;
683
+ goto clear_variables;
684
+ }
685
+ memcpy(mnemonic, mnemonic_input, num_chars * sizeof(char));
686
+ }
687
+
688
+ if (!storj_mnemonic_check(mnemonic)) {
689
+ printf("Encryption key integrity check failed.\n");
690
+ status = 1;
691
+ goto clear_variables;
692
+ }
693
+ }
694
+
695
+ if (!key) {
696
+ key = calloc(BUFSIZ, sizeof(char));
697
+ printf("We now need to save these settings. Please enter a passphrase" \
698
+ " to lock your settings.\n\n");
699
+ if (get_password_verify("Unlock passphrase: ", key, 0)) {
700
+ printf("Unable to store encrypted authentication.\n");
701
+ status = 1;
702
+ goto clear_variables;
703
+ }
704
+ printf("\n");
705
+ }
706
+
707
+ if (make_user_directory(root_dir)) {
708
+ status = 1;
709
+ goto clear_variables;
710
+ }
711
+
712
+ if (storj_encrypt_write_auth(user_file, key, user, pass, mnemonic)) {
713
+ status = 1;
714
+ printf("Failed to write to disk\n");
715
+ goto clear_variables;
716
+ }
717
+
718
+ printf("Successfully stored bridge username, password, and encryption "\
719
+ "key to %s\n\n",
720
+ user_file);
721
+
722
+ clear_variables:
723
+ if (user) {
724
+ free(user);
725
+ }
726
+ if (user_input) {
727
+ free(user_input);
728
+ }
729
+ if (pass) {
730
+ free(pass);
731
+ }
732
+ if (mnemonic) {
733
+ free(mnemonic);
734
+ }
735
+ if (mnemonic_input) {
736
+ free(mnemonic_input);
737
+ }
738
+ if (key) {
739
+ free(key);
740
+ }
741
+ if (root_dir) {
742
+ free(root_dir);
743
+ }
744
+ if (user_file) {
745
+ free(user_file);
746
+ }
747
+ if (host) {
748
+ free(host);
749
+ }
750
+
751
+ return status;
752
+ }
753
+
754
+ static void register_callback(uv_work_t *work_req, int status)
755
+ {
756
+ assert(status == 0);
757
+ json_request_t *req = work_req->data;
758
+
759
+ if (req->status_code != 201) {
760
+ printf("Request failed with status code: %i\n",
761
+ req->status_code);
762
+ struct json_object *error;
763
+ json_object_object_get_ex(req->response, "error", &error);
764
+ printf("Error: %s\n", json_object_get_string(error));
765
+
766
+ user_options_t *handle = (user_options_t *) req->handle;
767
+ free(handle->user);
768
+ free(handle->host);
769
+ free(handle->pass);
770
+ } else {
771
+ struct json_object *email;
772
+ json_object_object_get_ex(req->response, "email", &email);
773
+ printf("\n");
774
+ printf("Successfully registered %s, please check your email "\
775
+ "to confirm.\n", json_object_get_string(email));
776
+
777
+ // save credentials
778
+ char *mnemonic = NULL;
779
+ printf("\n");
780
+ generate_mnemonic(&mnemonic);
781
+ printf("\n");
782
+
783
+ printf("Encryption key: %s\n", mnemonic);
784
+ printf("\n");
785
+ printf("Please make sure to backup this key in a safe location. " \
786
+ "If the key is lost, the data uploaded will also be lost.\n\n");
787
+
788
+ user_options_t *user_opts = req->handle;
789
+
790
+ user_opts->mnemonic = mnemonic;
791
+ import_keys(user_opts);
792
+
793
+ if (mnemonic) {
794
+ free(mnemonic);
795
+ }
796
+ if (user_opts->pass) {
797
+ free(user_opts->pass);
798
+ }
799
+ if (user_opts->user) {
800
+ free(user_opts->user);
801
+ }
802
+ if (user_opts->host) {
803
+ free(user_opts->host);
804
+ }
805
+ }
806
+
807
+ json_object_put(req->response);
808
+ json_object_put(req->body);
809
+ free(req);
810
+ free(work_req);
811
+ }
812
+
813
+ static void list_files_callback(uv_work_t *work_req, int status)
814
+ {
815
+ int ret_status = 0;
816
+ assert(status == 0);
817
+ list_files_request_t *req = work_req->data;
818
+
819
+ if (req->status_code == 404) {
820
+ printf("Bucket id [%s] does not exist\n", req->bucket_id);
821
+ goto cleanup;
822
+ } else if (req->status_code == 400) {
823
+ printf("Bucket id [%s] is invalid\n", req->bucket_id);
824
+ goto cleanup;
825
+ } else if (req->status_code == 401) {
826
+ printf("Invalid user credentials.\n");
827
+ goto cleanup;
828
+ } else if (req->status_code != 200) {
829
+ printf("Request failed with status code: %i\n", req->status_code);
830
+ }
831
+
832
+ if (req->total_files == 0) {
833
+ printf("No files for bucket.\n");
834
+ }
835
+
836
+ for (int i = 0; i < req->total_files; i++) {
837
+
838
+ storj_file_meta_t *file = &req->files[i];
839
+
840
+ printf("ID: %s \tSize: %" PRIu64 " bytes \tDecrypted: %s \tType: %s \tCreated: %s \tName: %s\n",
841
+ file->id,
842
+ file->size,
843
+ file->decrypted ? "true" : "false",
844
+ file->mimetype,
845
+ file->created,
846
+ file->filename);
847
+ }
848
+
849
+ cleanup:
850
+ json_object_put(req->response);
851
+ storj_free_list_files_request(req);
852
+ free(work_req);
853
+ exit(ret_status);
854
+ }
855
+
856
+ static void delete_file_callback(uv_work_t *work_req, int status)
857
+ {
858
+ assert(status == 0);
859
+ json_request_t *req = work_req->data;
860
+
861
+ if (req->status_code == 200 || req->status_code == 204) {
862
+ printf("File was successfully removed from bucket.\n");
863
+ } else if (req->status_code == 401) {
864
+ printf("Invalid user credentials.\n");
865
+ } else {
866
+ printf("Failed to remove file from bucket. (%i)\n", req->status_code);
867
+ }
868
+
869
+ json_object_put(req->response);
870
+ free(req->path);
871
+ free(req);
872
+ free(work_req);
873
+ }
874
+
875
+ static void delete_bucket_callback(uv_work_t *work_req, int status)
876
+ {
877
+ assert(status == 0);
878
+ json_request_t *req = work_req->data;
879
+
880
+ if (req->status_code == 200 || req->status_code == 204) {
881
+ printf("Bucket was successfully removed.\n");
882
+ } else if (req->status_code == 401) {
883
+ printf("Invalid user credentials.\n");
884
+ } else {
885
+ printf("Failed to destroy bucket. (%i)\n", req->status_code);
886
+ }
887
+
888
+ json_object_put(req->response);
889
+ free(req->path);
890
+ free(req);
891
+ free(work_req);
892
+ }
893
+
894
+ static void get_buckets_callback(uv_work_t *work_req, int status)
895
+ {
896
+ assert(status == 0);
897
+ get_buckets_request_t *req = work_req->data;
898
+
899
+ if (req->status_code == 401) {
900
+ printf("Invalid user credentials.\n");
901
+ } else if (req->status_code != 200 && req->status_code != 304) {
902
+ printf("Request failed with status code: %i\n", req->status_code);
903
+ } else if (req->total_buckets == 0) {
904
+ printf("No buckets.\n");
905
+ }
906
+
907
+ for (int i = 0; i < req->total_buckets; i++) {
908
+ storj_bucket_meta_t *bucket = &req->buckets[i];
909
+ printf("ID: %s \tDecrypted: %s \tCreated: %s \tName: %s\n",
910
+ bucket->id, bucket->decrypted ? "true" : "false",
911
+ bucket->created, bucket->name);
912
+ }
913
+
914
+ json_object_put(req->response);
915
+ storj_free_get_buckets_request(req);
916
+ free(work_req);
917
+ }
918
+
919
+ static void create_bucket_callback(uv_work_t *work_req, int status)
920
+ {
921
+ assert(status == 0);
922
+ create_bucket_request_t *req = work_req->data;
923
+
924
+ if (req->status_code == 404) {
925
+ printf("Cannot create bucket [%s]. Name already exists \n", req->bucket->name);
926
+ goto clean_variables;
927
+ } else if (req->status_code == 401) {
928
+ printf("Invalid user credentials.\n");
929
+ goto clean_variables;
930
+ }
931
+
932
+ if (req->status_code != 201) {
933
+ printf("Request failed with status code: %i\n", req->status_code);
934
+ goto clean_variables;
935
+ }
936
+
937
+ if (req->bucket != NULL) {
938
+ printf("ID: %s \tDecrypted: %s \tName: %s\n",
939
+ req->bucket->id,
940
+ req->bucket->decrypted ? "true" : "false",
941
+ req->bucket->name);
942
+ } else {
943
+ printf("Failed to add bucket.\n");
944
+ }
945
+
946
+ clean_variables:
947
+ json_object_put(req->response);
948
+ free((char *)req->encrypted_bucket_name);
949
+ free(req->bucket);
950
+ free(req);
951
+ free(work_req);
952
+ }
953
+
954
+ static void get_info_callback(uv_work_t *work_req, int status)
955
+ {
956
+ assert(status == 0);
957
+ json_request_t *req = work_req->data;
958
+
959
+ if (req->error_code || req->response == NULL) {
960
+ free(req);
961
+ free(work_req);
962
+ if (req->error_code) {
963
+ printf("Request failed, reason: %s\n",
964
+ curl_easy_strerror(req->error_code));
965
+ } else {
966
+ printf("Failed to get info.\n");
967
+ }
968
+ exit(1);
969
+ }
970
+
971
+ struct json_object *info;
972
+ json_object_object_get_ex(req->response, "info", &info);
973
+
974
+ struct json_object *title;
975
+ json_object_object_get_ex(info, "title", &title);
976
+ struct json_object *description;
977
+ json_object_object_get_ex(info, "description", &description);
978
+ struct json_object *version;
979
+ json_object_object_get_ex(info, "version", &version);
980
+ struct json_object *host;
981
+ json_object_object_get_ex(req->response, "host", &host);
982
+
983
+ printf("Title: %s\n", json_object_get_string(title));
984
+ printf("Description: %s\n", json_object_get_string(description));
985
+ printf("Version: %s\n", json_object_get_string(version));
986
+ printf("Host: %s\n", json_object_get_string(host));
987
+
988
+ json_object_put(req->response);
989
+ free(req);
990
+ free(work_req);
991
+ }
992
+
993
+ static int export_keys(char *host)
994
+ {
995
+ int status = 0;
996
+ char *user_file = NULL;
997
+ char *root_dir = NULL;
998
+ char *user = NULL;
999
+ char *pass = NULL;
1000
+ char *mnemonic = NULL;
1001
+ char *key = NULL;
1002
+
1003
+ if (get_user_auth_location(host, &root_dir, &user_file)) {
1004
+ printf("Unable to determine user auth filepath.\n");
1005
+ status = 1;
1006
+ goto clear_variables;
1007
+ }
1008
+
1009
+ if (access(user_file, F_OK) != -1) {
1010
+ key = calloc(BUFSIZ, sizeof(char));
1011
+ printf("Unlock passphrase: ");
1012
+ get_password(key, '*');
1013
+ printf("\n\n");
1014
+
1015
+ if (storj_decrypt_read_auth(user_file, key, &user, &pass, &mnemonic)) {
1016
+ printf("Unable to read user file.\n");
1017
+ status = 1;
1018
+ goto clear_variables;
1019
+ }
1020
+
1021
+ printf("Username:\t%s\nPassword:\t%s\nEncryption key:\t%s\n",
1022
+ user, pass, mnemonic);
1023
+ }
1024
+
1025
+ clear_variables:
1026
+ if (user) {
1027
+ free(user);
1028
+ }
1029
+ if (pass) {
1030
+ free(pass);
1031
+ }
1032
+ if (mnemonic) {
1033
+ free(mnemonic);
1034
+ }
1035
+ if (root_dir) {
1036
+ free(root_dir);
1037
+ }
1038
+ if (user_file) {
1039
+ free(user_file);
1040
+ }
1041
+ if (key) {
1042
+ free(key);
1043
+ }
1044
+ return status;
1045
+ }
1046
+
1047
+ int main(int argc, char **argv)
1048
+ {
1049
+ int status = 0;
1050
+
1051
+ static struct option cmd_options[] = {
1052
+ {"url", required_argument, 0, 'u'},
1053
+ {"version", no_argument, 0, 'v'},
1054
+ {"proxy", required_argument, 0, 'p'},
1055
+ {"log", required_argument, 0, 'l'},
1056
+ {"debug", no_argument, 0, 'd'},
1057
+ {"help", no_argument, 0, 'h'},
1058
+ {0, 0, 0, 0}
1059
+ };
1060
+
1061
+ int index = 0;
1062
+
1063
+ // The default is usually 4 threads, we want to increase to the
1064
+ // locally set default value.
1065
+ #ifdef _WIN32
1066
+ if (!getenv("UV_THREADPOOL_SIZE")) {
1067
+ _putenv_s("UV_THREADPOOL_SIZE", STORJ_THREADPOOL_SIZE);
1068
+ }
1069
+ #else
1070
+ setenv("UV_THREADPOOL_SIZE", STORJ_THREADPOOL_SIZE, 0);
1071
+ #endif
1072
+
1073
+ char *storj_bridge = getenv("STORJ_BRIDGE");
1074
+ int c;
1075
+ int log_level = 0;
1076
+
1077
+ char *proxy = getenv("STORJ_PROXY");
1078
+
1079
+ while ((c = getopt_long_only(argc, argv, "hdl:p:vVu:",
1080
+ cmd_options, &index)) != -1) {
1081
+ switch (c) {
1082
+ case 'u':
1083
+ storj_bridge = optarg;
1084
+ break;
1085
+ case 'p':
1086
+ proxy = optarg;
1087
+ break;
1088
+ case 'l':
1089
+ log_level = atoi(optarg);
1090
+ break;
1091
+ case 'd':
1092
+ log_level = 4;
1093
+ break;
1094
+ case 'V':
1095
+ case 'v':
1096
+ printf(CLI_VERSION "\n\n");
1097
+ exit(0);
1098
+ break;
1099
+ case 'h':
1100
+ printf(HELP_TEXT);
1101
+ exit(0);
1102
+ break;
1103
+ }
1104
+ }
1105
+
1106
+ if (log_level > 4 || log_level < 0) {
1107
+ printf("Invalid log level\n");
1108
+ return 1;
1109
+ }
1110
+
1111
+ int command_index = optind;
1112
+
1113
+ char *command = argv[command_index];
1114
+ if (!command) {
1115
+ printf(HELP_TEXT);
1116
+ return 0;
1117
+ }
1118
+
1119
+ if (!storj_bridge) {
1120
+ storj_bridge = "https://api.storj.io:443/";
1121
+ }
1122
+
1123
+ // Parse the host, part and proto from the storj bridge url
1124
+ char proto[6];
1125
+ char host[100];
1126
+ int port = 0;
1127
+ sscanf(storj_bridge, "%5[^://]://%99[^:/]:%99d", proto, host, &port);
1128
+
1129
+ if (port == 0) {
1130
+ if (strcmp(proto, "https") == 0) {
1131
+ port = 443;
1132
+ } else {
1133
+ port = 80;
1134
+ }
1135
+ }
1136
+
1137
+ if (strcmp(command, "login") == 0) {
1138
+ printf("'login' is not a storj command. Did you mean 'import-keys'?\n\n");
1139
+ return 1;
1140
+ }
1141
+
1142
+ if (strcmp(command, "import-keys") == 0) {
1143
+ user_options_t user_options = {NULL, NULL, host, NULL, NULL};
1144
+ return import_keys(&user_options);
1145
+ }
1146
+
1147
+ if (strcmp(command, "export-keys") == 0) {
1148
+ return export_keys(host);
1149
+ }
1150
+
1151
+ // initialize event loop and environment
1152
+ storj_env_t *env = NULL;
1153
+
1154
+ storj_http_options_t http_options = {
1155
+ .user_agent = CLI_VERSION,
1156
+ .low_speed_limit = STORJ_LOW_SPEED_LIMIT,
1157
+ .low_speed_time = STORJ_LOW_SPEED_TIME,
1158
+ .timeout = STORJ_HTTP_TIMEOUT
1159
+ };
1160
+
1161
+ storj_log_options_t log_options = {
1162
+ .logger = json_logger,
1163
+ .level = log_level
1164
+ };
1165
+
1166
+ if (proxy) {
1167
+ http_options.proxy_url = proxy;
1168
+ } else {
1169
+ http_options.proxy_url = NULL;
1170
+ }
1171
+
1172
+ char *user = NULL;
1173
+ char *pass = NULL;
1174
+ char *mnemonic = NULL;
1175
+
1176
+ if (strcmp(command, "get-info") == 0) {
1177
+ printf("Storj bridge: %s\n\n", storj_bridge);
1178
+
1179
+ storj_bridge_options_t options = {
1180
+ .proto = proto,
1181
+ .host = host,
1182
+ .port = port,
1183
+ .user = NULL,
1184
+ .pass = NULL
1185
+ };
1186
+
1187
+ env = storj_init_env(&options, NULL, &http_options, &log_options);
1188
+ if (!env) {
1189
+ return 1;
1190
+ }
1191
+
1192
+ storj_bridge_get_info(env, NULL, get_info_callback);
1193
+
1194
+ } else if(strcmp(command, "register") == 0) {
1195
+ storj_bridge_options_t options = {
1196
+ .proto = proto,
1197
+ .host = host,
1198
+ .port = port,
1199
+ .user = NULL,
1200
+ .pass = NULL
1201
+ };
1202
+
1203
+ env = storj_init_env(&options, NULL, &http_options, &log_options);
1204
+ if (!env) {
1205
+ return 1;
1206
+ }
1207
+
1208
+ user = calloc(BUFSIZ, sizeof(char));
1209
+ if (!user) {
1210
+ return 1;
1211
+ }
1212
+ printf("Bridge username (email): ");
1213
+ get_input(user);
1214
+
1215
+ printf("Bridge password: ");
1216
+ pass = calloc(BUFSIZ, sizeof(char));
1217
+ if (!pass) {
1218
+ return 1;
1219
+ }
1220
+ get_password(pass, '*');
1221
+ printf("\n");
1222
+
1223
+ user_options_t user_opts = {strdup(user), strdup(pass), strdup(host), NULL, NULL};
1224
+
1225
+ if (!user_opts.user || !user_opts.host || !user_opts.pass) {
1226
+ return 1;
1227
+ }
1228
+
1229
+ storj_bridge_register(env, user, pass, &user_opts, register_callback);
1230
+ } else {
1231
+
1232
+ char *user_file = NULL;
1233
+ char *root_dir = NULL;
1234
+ if (get_user_auth_location(host, &root_dir, &user_file)) {
1235
+ printf("Unable to determine user auth filepath.\n");
1236
+ return 1;
1237
+ }
1238
+
1239
+ // We aren't using root dir so free it
1240
+ free(root_dir);
1241
+
1242
+ // First, get auth from environment variables
1243
+ user = getenv("STORJ_BRIDGE_USER") ?
1244
+ strdup(getenv("STORJ_BRIDGE_USER")) : NULL;
1245
+
1246
+ pass = getenv("STORJ_BRIDGE_PASS") ?
1247
+ strdup(getenv("STORJ_BRIDGE_PASS")) : NULL;
1248
+
1249
+ mnemonic = getenv("STORJ_ENCRYPTION_KEY") ?
1250
+ strdup(getenv("STORJ_ENCRYPTION_KEY")) : NULL;
1251
+
1252
+ char *keypass = getenv("STORJ_KEYPASS");
1253
+
1254
+ // Second, try to get from encrypted user file
1255
+ if ((!user || !pass || !mnemonic) && access(user_file, F_OK) != -1) {
1256
+
1257
+ char *key = NULL;
1258
+ if (keypass) {
1259
+ key = calloc(strlen(keypass) + 1, sizeof(char));
1260
+ if (!key) {
1261
+ return 1;
1262
+ }
1263
+ strcpy(key, keypass);
1264
+ } else {
1265
+ key = calloc(BUFSIZ, sizeof(char));
1266
+ if (!key) {
1267
+ return 1;
1268
+ }
1269
+ printf("Unlock passphrase: ");
1270
+ get_password(key, '*');
1271
+ printf("\n");
1272
+ }
1273
+ char *file_user = NULL;
1274
+ char *file_pass = NULL;
1275
+ char *file_mnemonic = NULL;
1276
+ if (storj_decrypt_read_auth(user_file, key, &file_user,
1277
+ &file_pass, &file_mnemonic)) {
1278
+ printf("Unable to read user file. Invalid keypass or path.\n");
1279
+ free(key);
1280
+ free(user_file);
1281
+ free(file_user);
1282
+ free(file_pass);
1283
+ free(file_mnemonic);
1284
+ goto end_program;
1285
+ }
1286
+ free(key);
1287
+ free(user_file);
1288
+
1289
+ if (!user && file_user) {
1290
+ user = file_user;
1291
+ } else if (file_user) {
1292
+ free(file_user);
1293
+ }
1294
+
1295
+ if (!pass && file_pass) {
1296
+ pass = file_pass;
1297
+ } else if (file_pass) {
1298
+ free(file_pass);
1299
+ }
1300
+
1301
+ if (!mnemonic && file_mnemonic) {
1302
+ mnemonic = file_mnemonic;
1303
+ } else if (file_mnemonic) {
1304
+ free(file_mnemonic);
1305
+ }
1306
+
1307
+ }
1308
+
1309
+ // Third, ask for authentication
1310
+ if (!user) {
1311
+ char *user_input = malloc(BUFSIZ);
1312
+ if (user_input == NULL) {
1313
+ return 1;
1314
+ }
1315
+ printf("Bridge username (email): ");
1316
+ get_input(user_input);
1317
+ int num_chars = strlen(user_input);
1318
+ user = calloc(num_chars + 1, sizeof(char));
1319
+ if (!user) {
1320
+ return 1;
1321
+ }
1322
+ memcpy(user, user_input, num_chars);
1323
+ free(user_input);
1324
+ }
1325
+
1326
+ if (!pass) {
1327
+ printf("Bridge password: ");
1328
+ pass = calloc(BUFSIZ, sizeof(char));
1329
+ if (!pass) {
1330
+ return 1;
1331
+ }
1332
+ get_password(pass, '*');
1333
+ printf("\n");
1334
+ }
1335
+
1336
+ if (!mnemonic) {
1337
+ printf("Encryption key: ");
1338
+ char *mnemonic_input = malloc(BUFSIZ);
1339
+ if (mnemonic_input == NULL) {
1340
+ return 1;
1341
+ }
1342
+ get_input(mnemonic_input);
1343
+ int num_chars = strlen(mnemonic_input);
1344
+ mnemonic = calloc(num_chars + 1, sizeof(char));
1345
+ if (!mnemonic) {
1346
+ return 1;
1347
+ }
1348
+ memcpy(mnemonic, mnemonic_input, num_chars);
1349
+ free(mnemonic_input);
1350
+ printf("\n");
1351
+ }
1352
+
1353
+ storj_bridge_options_t options = {
1354
+ .proto = proto,
1355
+ .host = host,
1356
+ .port = port,
1357
+ .user = user,
1358
+ .pass = pass
1359
+ };
1360
+
1361
+ storj_encrypt_options_t encrypt_options = {
1362
+ .mnemonic = mnemonic
1363
+ };
1364
+
1365
+ env = storj_init_env(&options, &encrypt_options,
1366
+ &http_options, &log_options);
1367
+ if (!env) {
1368
+ status = 1;
1369
+ goto end_program;
1370
+ }
1371
+
1372
+ if (strcmp(command, "download-file") == 0) {
1373
+ char *bucket_id = argv[command_index + 1];
1374
+ char *file_id = argv[command_index + 2];
1375
+ char *path = argv[command_index + 3];
1376
+
1377
+ if (!bucket_id || !file_id || !path) {
1378
+ printf("Missing arguments: <bucket-id> <file-id> <path>\n");
1379
+ status = 1;
1380
+ goto end_program;
1381
+ }
1382
+
1383
+ if (download_file(env, bucket_id, file_id, path)) {
1384
+ status = 1;
1385
+ goto end_program;
1386
+ }
1387
+ } else if (strcmp(command, "upload-file") == 0) {
1388
+ char *bucket_id = argv[command_index + 1];
1389
+ char *path = argv[command_index + 2];
1390
+
1391
+ if (!bucket_id || !path) {
1392
+ printf("Missing arguments: <bucket-id> <path>\n");
1393
+ status = 1;
1394
+ goto end_program;
1395
+ }
1396
+
1397
+ if (upload_file(env, bucket_id, path)) {
1398
+ status = 1;
1399
+ goto end_program;
1400
+ }
1401
+ } else if (strcmp(command, "list-files") == 0) {
1402
+ char *bucket_id = argv[command_index + 1];
1403
+
1404
+ if (!bucket_id) {
1405
+ printf("Missing first argument: <bucket-id>\n");
1406
+ status = 1;
1407
+ goto end_program;
1408
+ }
1409
+
1410
+ storj_bridge_list_files(env, bucket_id, NULL, list_files_callback);
1411
+ } else if (strcmp(command, "add-bucket") == 0) {
1412
+ char *bucket_name = argv[command_index + 1];
1413
+
1414
+ if (!bucket_name) {
1415
+ printf("Missing first argument: <bucket-name>\n");
1416
+ status = 1;
1417
+ goto end_program;
1418
+ }
1419
+
1420
+ storj_bridge_create_bucket(env, bucket_name,
1421
+ NULL, create_bucket_callback);
1422
+
1423
+ } else if (strcmp(command, "remove-bucket") == 0) {
1424
+ char *bucket_id = argv[command_index + 1];
1425
+
1426
+ if (!bucket_id) {
1427
+ printf("Missing first argument: <bucket-id>\n");
1428
+ status = 1;
1429
+ goto end_program;
1430
+ }
1431
+
1432
+ storj_bridge_delete_bucket(env, bucket_id, NULL,
1433
+ delete_bucket_callback);
1434
+
1435
+ } else if (strcmp(command, "remove-file") == 0) {
1436
+ char *bucket_id = argv[command_index + 1];
1437
+ char *file_id = argv[command_index + 2];
1438
+
1439
+ if (!bucket_id || !file_id) {
1440
+ printf("Missing arguments, expected: <bucket-id> <file-id>\n");
1441
+ status = 1;
1442
+ goto end_program;
1443
+ }
1444
+ storj_bridge_delete_file(env, bucket_id, file_id,
1445
+ NULL, delete_file_callback);
1446
+
1447
+ } else if (strcmp(command, "list-buckets") == 0) {
1448
+ storj_bridge_get_buckets(env, NULL, get_buckets_callback);
1449
+ } else if (strcmp(command, "list-mirrors") == 0) {
1450
+ char *bucket_id = argv[command_index + 1];
1451
+ char *file_id = argv[command_index + 2];
1452
+
1453
+ if (!bucket_id || !file_id) {
1454
+ printf("Missing arguments, expected: <bucket-id> <file-id>\n");
1455
+ status = 1;
1456
+ goto end_program;
1457
+ }
1458
+ storj_bridge_list_mirrors(env, bucket_id, file_id,
1459
+ NULL, list_mirrors_callback);
1460
+ } else {
1461
+ printf("'%s' is not a storj command. See 'storj --help'\n\n",
1462
+ command);
1463
+ status = 1;
1464
+ goto end_program;
1465
+ }
1466
+
1467
+ }
1468
+
1469
+ // run all queued events
1470
+ if (uv_run(env->loop, UV_RUN_DEFAULT)) {
1471
+ uv_loop_close(env->loop);
1472
+
1473
+ // cleanup
1474
+ storj_destroy_env(env);
1475
+
1476
+ status = 1;
1477
+ goto end_program;
1478
+ }
1479
+
1480
+ end_program:
1481
+ if (env) {
1482
+ storj_destroy_env(env);
1483
+ }
1484
+ if (user) {
1485
+ free(user);
1486
+ }
1487
+ if (pass) {
1488
+ free(pass);
1489
+ }
1490
+ if (mnemonic) {
1491
+ free(mnemonic);
1492
+ }
1493
+ return status;
1494
+ }