├── .gitignore ├── LICENSE ├── README.md ├── bin └── imgbi-client ├── lib └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013, img.bi project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imgbi-client 2 | Simple command-line client and Node.js library for use [img.bi](https://img.bi). 3 | 4 | ## Install 5 | 6 | npm install imgbi -g 7 | 8 | ## Usage 9 | 10 | ~~~ sh 11 | $ imgbi-client -i image.png 12 | https://img.bi/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam 13 | https://img.bi/rm/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam!Rl80pmqeXIgRhZz9TQvCrYLAIAi 14 | 15 | $ imgbi-client -d 'https://img.bi/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam' -o images 16 | OK: Saved to XqL4IVp.png 17 | 18 | $ imgbi-client -r 'https://img.bi/rm/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam!Rl80pmqeXIgRhZz9TQvCrYLAIAi' 19 | OK: Removed 20 | 21 | ~~~ 22 | 23 | ## --help 24 | 25 | Usage: 26 | imgbi-client [OPTIONS] [ARGS] 27 | 28 | Options: 29 | -i, --image FILE Image location 30 | -r, --remove URL URL of file to be removed 31 | -d, --download URL URL of file to be downloaded and decrypted 32 | -e, --expire [NUMBER] Set expire time in days for image, 0 for store forever (Default is 180) 33 | -o, --output [PATH] Location to save file (Default is .) 34 | -u, --url [URL] URL of img.bi instance (Default is https://img.bi) 35 | -n, --norm Don't print removal link 36 | -l, --nolink Don't print link to show image 37 | -a, --autorm Print autoremove link 38 | -em, --embed Print embed code 39 | -k, --no-color Omit color from output 40 | --debug Show debug information 41 | -h, --help Display help and usage details 42 | 43 | 44 | ## Programmatic usage 45 | ### Uploading 46 | 47 | ~~~ js 48 | var imgbi = require('imgbi'); 49 | var options = {}; 50 | options.image = 'image.jpg'; // image location 51 | options.expire = '180'; // time to expire in days, default 180 52 | options.url = 'https://img.bi'; // url of img.bi server, https://img.bi by default 53 | 54 | imgbi.upload(options, function(err, result) { 55 | if (err) { 56 | new Error(err); // if there any error during the upload 57 | } 58 | else { 59 | console.log(result.id); // id of file 60 | console.log(result.pass); // pass used for encryption 61 | console.log(result.removalpass); // pass for remove file 62 | console.log(result.viewlink); // link to view image 63 | console.log(result.rmlink); // link to remove image 64 | console.log(result.autormlink); // link to autoremove image after first view 65 | console.log(result.embedcode); // code to embed image using img.bi.js script 66 | } 67 | }); 68 | ~~~ 69 | 70 | ### Removing 71 | 72 | ~~~ js 73 | imgbi = require('imgbi'); 74 | 75 | var url = 'https://img.bi/rm/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam!Rl80pmqeXIgRhZz9TQvCrYLAIAi'; // link to remove image 76 | 77 | imgbi.remove(url, function(err) { 78 | if (err) { 79 | new Error(err); // if there any error during the remove 80 | } 81 | else { 82 | console.log('Removed'); 83 | } 84 | }); 85 | ~~~ 86 | 87 | ### Downloading 88 | 89 | ~~~ js 90 | imgbi = require('imgbi'); 91 | 92 | var url = 'https://img.bi/#!XqL4IVp!jxJccrgkodebbxlaplteabgtbkllab5tberiWkam'; // link to view image 93 | var path = '~/images'; // path to save image 94 | 95 | imgbi.download(url, path, function(err, result) { 96 | if (err) { 97 | new Error(err); // if there any error during the download 98 | } 99 | else { 100 | console.log(result); // filename 101 | } 102 | }); 103 | ~~~ 104 | -------------------------------------------------------------------------------- /bin/imgbi-client: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var cli = require('cli').enable('status'), 3 | imgbi = require('..'), 4 | EOL = require('os').EOL; 5 | cli.parse({ 6 | image: ['i', 'Image location', 'file'], 7 | remove: ['r', 'URL of file to be removed', 'url'], 8 | download: ['d', 'URL of file to be downloaded and decrypted', 'url'], 9 | expire: ['e', 'Set expire time in days for image, 0 for store forever', 'number', '180'], 10 | output: ['o', 'Location to save file', 'path', '.'], 11 | url: ['u', 'URL of img.bi instance', 'url', 'https://img.bi'], 12 | norm: ['n', 'Don\'t print removal link'], 13 | nolink: ['l', 'Don\'t print link to show image'], 14 | autorm: ['a', 'Print autoremove link'], 15 | embed: ['em', 'Print embed code'] 16 | }); 17 | 18 | cli.main(function(args, options) { 19 | if (options.image) { 20 | imgbi.upload({file: options.image, url: options.url, expire: options.expire}, function(err, result) { 21 | if (err) { 22 | cli.fatal(err.message); 23 | } 24 | cli.debug(JSON.stringify(result)); 25 | if (! options.nolink) { 26 | cli.output(result.viewlink + EOL); 27 | } 28 | if (! options.norm) { 29 | cli.output(result.rmlink + EOL); 30 | } 31 | if (options.autorm) { 32 | cli.output(result.autormlink + EOL); 33 | } 34 | if (options.embed) { 35 | cli.output(result.embedcode + EOL); 36 | } 37 | }); 38 | } 39 | else if (options.remove) { 40 | imgbi.remove(options.remove, function(err) { 41 | if (err) { 42 | cli.fatal(err); 43 | } 44 | else { 45 | cli.ok('Removed'); 46 | } 47 | }); 48 | } 49 | else if (options.download) { 50 | imgbi.download(options.download, options.output, function(err, result) { 51 | if (err) { 52 | cli.fatal(err); 53 | } 54 | else { 55 | cli.ok('Saved as ' + result); 56 | } 57 | }); 58 | } 59 | else { 60 | this.fatal('Nothing to do.'); 61 | } 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var sjcl = require('sjcl'), 3 | datauri = require('datauri'), 4 | Passwordgen = require('passwordgen'), 5 | needle = require('needle'), 6 | mime = require('mime'), 7 | fs = require('fs'), 8 | gen = new Passwordgen().secure(), 9 | im = require('imagemagick'), 10 | tmp = require('tmp'); 11 | 12 | module.exports.upload = function(options, next) { 13 | if (! 'url' in options) { 14 | options.url = 'https://img.bi'; 15 | } 16 | if (! 'expire' in options) { 17 | options.expire = 180; 18 | } 19 | var acceptedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml', 'image/webp'], 20 | maxSize = 5242880, 21 | mimetype = mime.lookup(options.file); 22 | if (acceptedTypes.indexOf(mimetype) == '-1') { 23 | next(new Error('Mime type ' + mimetype + ' is not supported')); 24 | } 25 | var uri = new datauri(options.file).content, 26 | pass = gen.chars(40), 27 | encrypted = sjcl.encrypt(pass, uri, {ks:256}), 28 | filesize = Buffer.byteLength(encrypted), 29 | params = { 30 | compressed: true, 31 | parse: true, 32 | headers: { 33 | 'Content-length': filesize 34 | }, 35 | timeout: 100000 36 | }; 37 | if (filesize > maxSize) { 38 | next(new Error('File is too big, limit is ' + maxSize + ' bytes of encrypted text')); 39 | } 40 | tmp.file({ postfix: '.jpg' }, function _tempFileCreated(err, path, fd) { 41 | if (err) throw next(new Error(err)); 42 | im.resize({ 43 | srcPath: options.file, 44 | dstPath: path, 45 | width: 300, 46 | quality: 0.85, 47 | format: 'jpg' 48 | },function(err, stdout){ 49 | if (err) throw next(new Error(err)); 50 | ethumb = sjcl.encrypt(pass, new datauri(path).content, {ks:256}); 51 | needle.post(options.url + '/api/upload', {encrypted: encrypted, thumb: ethumb, expire: options.expire}, params, function(error, response, body) { 52 | if (!error && response.statusCode == 200) { 53 | if (body.status == 'OK') { 54 | next(null, { 55 | id: body.id, 56 | pass: pass, 57 | removalpass: body.pass, 58 | viewlink: options.url + '/#/' + body.id + '!' + pass, 59 | rmlink: options.url + '/#/rm/' + body.id + '!' + pass + '!' + body.pass, 60 | autormlink: options.url + '/#autorm/' + body.id + '!' + pass + '!' + body.pass, 61 | embedcode: '' 62 | }); 63 | } 64 | else { 65 | next(new Error(body.status)); 66 | } 67 | } 68 | else { 69 | next(new Error(error)); 70 | } 71 | }); 72 | }); 73 | }); 74 | } 75 | module.exports.remove = function(url, next) { 76 | var params = url.split('!'), 77 | host = params[0].split('#')[0], 78 | id = params[0].slice(-7), 79 | pass = params[1], 80 | removalpass = params[2]; 81 | rqparams = { 82 | compressed: true, 83 | parse: true 84 | }; 85 | needle.get(host + 'api/remove?id=' + id + '&password=' + removalpass, rqparams, function(error, response, body) { 86 | if (!error && response.statusCode == 200) { 87 | if (body.status == 'Success') { 88 | next(null); 89 | } 90 | else { 91 | next(new Error(body.status)); 92 | } 93 | } 94 | else { 95 | next(new Error(error)); 96 | } 97 | }); 98 | } 99 | 100 | module.exports.download = function(url, path, next) { 101 | 102 | var params = url.split('!'), 103 | host = params[0].split('#')[0], 104 | id = params[0].slice(-7), 105 | pass = params[1]; 106 | rqparams = { 107 | compressed: true, 108 | parse: false 109 | }; 110 | needle.get(host + 'download/' + id, rqparams, function(error, response, body) { 111 | if (!error && response.statusCode == 200) { 112 | var decrypted = sjcl.decrypt(pass,body.toString()); 113 | var data = decrypted.match(/^data:image\/(.+);base64,(.*)$/); 114 | fs.writeFile(path + '/' + id + '.' + data[1].replace('+xml', ''), data[2], 'base64', function(err) { 115 | if (err) { 116 | next(new Error(err)); 117 | } 118 | else { 119 | next(null,id + '.' + data[1].replace('+xml','')); 120 | } 121 | }); 122 | } 123 | else if (error) { 124 | next(new Error(error)); 125 | } 126 | else if (response.statusCode != 200) { 127 | next(new Error(response.statusCode)); 128 | } 129 | }); 130 | } 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgbi", 3 | "version": "0.0.6", 4 | "preferGlobal": true, 5 | "description": "Simple command-line client and Node.js library for use img.bi.", 6 | "keywords": [ 7 | "img.bi", 8 | "uploader", 9 | "downloader", 10 | "crypto", 11 | "image", 12 | "images" 13 | ], 14 | "main": "lib/index.js", 15 | "bin": { 16 | "imgbi-client": "bin/imgbi-client" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/imgbi/imgbi-client.git" 21 | }, 22 | "author": "Anton Nesterov", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/imgbi/imgbi-client/issues", 26 | "email": "bugs@img.bi" 27 | }, 28 | "dependencies": { 29 | "cli": "~0.8.0", 30 | "datauri": "~0.7.1", 31 | "imagemagick": "~0.1.3", 32 | "mime": "~1.3.4", 33 | "needle": "^0.10.0", 34 | "passwordgen": "^0.3.0", 35 | "sjcl": "^1.0.3", 36 | "tmp": "0.0.26" 37 | } 38 | } 39 | --------------------------------------------------------------------------------