ruby-libstorj 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +111 -0
  7. data/Guardfile +21 -0
  8. data/LICENSE +502 -0
  9. data/README.md +262 -0
  10. data/Rakefile +76 -0
  11. data/ext/libstorj/.gitignore +47 -0
  12. data/ext/libstorj/.travis.yml +27 -0
  13. data/ext/libstorj/Doxyfile +2427 -0
  14. data/ext/libstorj/LICENSE +502 -0
  15. data/ext/libstorj/Makefile.am +6 -0
  16. data/ext/libstorj/README.md +198 -0
  17. data/ext/libstorj/autogen.sh +3 -0
  18. data/ext/libstorj/configure.ac +64 -0
  19. data/ext/libstorj/depends/Makefile +153 -0
  20. data/ext/libstorj/depends/config.guess +1462 -0
  21. data/ext/libstorj/depends/config.sub +1823 -0
  22. data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
  23. data/ext/libstorj/depends/packages/cctools.mk +7 -0
  24. data/ext/libstorj/depends/packages/clang.mk +7 -0
  25. data/ext/libstorj/depends/packages/gmp.mk +23 -0
  26. data/ext/libstorj/depends/packages/gnutls.mk +25 -0
  27. data/ext/libstorj/depends/packages/json-c.mk +7 -0
  28. data/ext/libstorj/depends/packages/libcurl.mk +39 -0
  29. data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
  30. data/ext/libstorj/depends/packages/libuv.mk +7 -0
  31. data/ext/libstorj/depends/packages/nettle.mk +30 -0
  32. data/ext/libstorj/libstorj.pc.in +11 -0
  33. data/ext/libstorj/src/Makefile.am +23 -0
  34. data/ext/libstorj/src/bip39.c +233 -0
  35. data/ext/libstorj/src/bip39.h +64 -0
  36. data/ext/libstorj/src/bip39_english.h +2074 -0
  37. data/ext/libstorj/src/cli.c +1494 -0
  38. data/ext/libstorj/src/crypto.c +525 -0
  39. data/ext/libstorj/src/crypto.h +178 -0
  40. data/ext/libstorj/src/downloader.c +1923 -0
  41. data/ext/libstorj/src/downloader.h +163 -0
  42. data/ext/libstorj/src/http.c +688 -0
  43. data/ext/libstorj/src/http.h +175 -0
  44. data/ext/libstorj/src/rs.c +962 -0
  45. data/ext/libstorj/src/rs.h +99 -0
  46. data/ext/libstorj/src/storj.c +1523 -0
  47. data/ext/libstorj/src/storj.h +1014 -0
  48. data/ext/libstorj/src/uploader.c +2736 -0
  49. data/ext/libstorj/src/uploader.h +181 -0
  50. data/ext/libstorj/src/utils.c +336 -0
  51. data/ext/libstorj/src/utils.h +65 -0
  52. data/ext/libstorj/test/Makefile.am +27 -0
  53. data/ext/libstorj/test/mockbridge.c +260 -0
  54. data/ext/libstorj/test/mockbridge.json +687 -0
  55. data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
  56. data/ext/libstorj/test/mockfarmer.c +358 -0
  57. data/ext/libstorj/test/storjtests.h +41 -0
  58. data/ext/libstorj/test/tests.c +1617 -0
  59. data/ext/libstorj/test/tests_rs.c +869 -0
  60. data/ext/ruby-libstorj/extconf.rb +8 -0
  61. data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
  62. data/lib/ruby-libstorj.rb +1 -0
  63. data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
  64. data/lib/ruby-libstorj/env.rb +178 -0
  65. data/lib/ruby-libstorj/ext/bucket.rb +71 -0
  66. data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
  67. data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
  68. data/lib/ruby-libstorj/ext/ext.rb +71 -0
  69. data/lib/ruby-libstorj/ext/file.rb +84 -0
  70. data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
  71. data/lib/ruby-libstorj/ext/json_request.rb +51 -0
  72. data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
  73. data/lib/ruby-libstorj/ext/types.rb +226 -0
  74. data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
  75. data/lib/ruby-libstorj/libstorj.rb +22 -0
  76. data/lib/ruby-libstorj/mixins/storj.rb +27 -0
  77. data/lib/ruby-libstorj/struct.rb +42 -0
  78. data/ruby-libstorj.gemspec +57 -0
  79. data/spec/helpers/options.yml.example +22 -0
  80. data/spec/helpers/shared_rake_examples.rb +132 -0
  81. data/spec/helpers/storj_options.rb +96 -0
  82. data/spec/helpers/upload.data +3 -0
  83. data/spec/helpers/upload.data.sha256 +1 -0
  84. data/spec/libstorj_spec.rb +0 -0
  85. data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
  86. data/spec/ruby-libstorj/env_spec.rb +353 -0
  87. data/spec/ruby-libstorj/ext_spec.rb +75 -0
  88. data/spec/ruby-libstorj/json_request_spec.rb +13 -0
  89. data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
  90. data/spec/ruby-libstorj/struct_spec.rb +64 -0
  91. data/spec/spec_helper.rb +113 -0
  92. metadata +136 -0
@@ -0,0 +1,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
+ }