| #!/opt/node/bin/node |
| |
| /* |
| Copyright 2015-2018 Rivoreo |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| "Software"), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE |
| FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| // TODO: check host key of the server |
| |
| const DEFAULT_PORT = 22; |
| const DEFAULT_USER_NAME = "sshout"; |
| |
| var fs = require("fs"); |
| var util = require("util"); |
| var sshout = require("sshout"); |
| var ALGORITHMS = require("ssh2-streams").constants.ALGORITHMS; |
| var os = require("os"); |
| var url = require("url"); |
| var crypto = require("crypto"); |
| |
| var StringStartsWith = function(s, sub) { |
| if(s.length < sub.length) return false; |
| for(var i=0; i<sub.length; i++) { |
| if(s[i] != sub[i]) return false; |
| } |
| return true; |
| }; |
| |
| var print_usage = function(name) { |
| process.stderr.write(util.format("Usage: %s [-i <identify-file>] [-v] ssh://[<user-name>@]<sshout-server>[:<port>][/] <image-dir> <reply-url>\n", name)); |
| }; |
| |
| var server_url = null; |
| var image_dir = null; |
| var reply_url = null; |
| //var identify_files = []; |
| var identify_file = null; |
| var verbose = 0; |
| |
| for(var i=2; i<process.argv.length; i++) { |
| if(process.argv[i][0] == "-") { |
| var o = process.argv[i]; |
| for(var j=1; j<o.length; j++) switch(o[j]) { |
| case "h": |
| print_usage(process.argv[1]); |
| process.exit(0); |
| break; |
| case "i": |
| if(++i >= process.argv.length) fatal_option_require_argument("u"); |
| //identify_files.push(process.argv[i]); |
| identify_file = process.argv[i]; |
| break; |
| case "v": |
| verbose++; |
| break; |
| } |
| } else if(server_url === null) { |
| //url = new URL(process.argv[i]); |
| server_url = url.parse(process.argv[i], false, false); |
| if(server_url.protocol !== "ssh:") { |
| process.stderr.write("Protocol name in URL must be 'ssh'\n"); |
| process.exit(-1); |
| } |
| } else if(image_dir === null) { |
| image_dir = process.argv[i]; |
| if(!fs.existsSync(image_dir)) fs.mkdirSync(image_dir, 0755); |
| } else if(reply_url === null) { |
| reply_url = process.argv[i]; |
| if(reply_url[reply_url.length - 1] === "/") reply_url = reply_url.substring(0, reply_url.length - 1); |
| } else { |
| process.stderr.write("Extra string after URL\n"); |
| process.exit(-1); |
| } |
| } |
| |
| if(server_url === null) { |
| process.stderr.write("Need an SSH URL\n"); |
| print_usage(process.argv[1]); |
| process.exit(-1); |
| } |
| if(image_dir === null) { |
| process.stderr.write("Need image directory path\n"); |
| print_usage(process.argv[1]); |
| process.exit(-1); |
| } |
| if(reply_url === null) { |
| process.stderr.write("Need reply URL\n"); |
| print_usage(process.argv[1]); |
| process.exit(-1); |
| } |
| |
| var kex_list = ALGORITHMS.SUPPORTED_KEX; |
| |
| var request_user_name = server_url.auth; |
| if(request_user_name === null) { |
| request_user_name = DEFAULT_USER_NAME; |
| } else { |
| var colon_i = request_user_name.indexOf(":"); |
| if(colon_i !== -1) request_user_name = request_user_name.substring(0, last_i); |
| } |
| |
| var private_key = identify_file === null ? null : fs.readFileSync(identify_file); |
| |
| var debug_print = verbose ? function(s) { |
| if(verbose < 2 && StringStartsWith(s, "DEBUG: Parser: ")) return; |
| process.stderr.write(s); |
| process.stderr.write("\n"); |
| } : null; |
| |
| var sshout_client = new sshout.Client({ |
| algorithms:{ kex:kex_list }, |
| host:server_url.hostname, |
| port:server_url.port ? server_url.port : DEFAULT_PORT, |
| username:request_user_name, |
| privateKey:private_key, |
| tryKeyboard:true, // Needed for public chatrooms |
| keepaliveInterval:240000, |
| debug:debug_print |
| }); |
| |
| var sshout_canoncal_user_name; |
| |
| sshout_client.on("ready", function(canoncal_user_name) { |
| sshout_canoncal_user_name = canoncal_user_name; |
| }); |
| sshout_client.on("error", function(e, msg) { |
| switch(typeof e) { |
| case "number": |
| process.stderr.write(util.format("SSHOUT error %d, %s\n", e, msg)); |
| break; |
| case "object": |
| console.error(e); |
| break; |
| default: |
| process.stderr.wrtie(util.format("unknown type of error event (%s)\n", typeof e)); |
| break; |
| } |
| }); |
| sshout_client.on("message", function(o) { |
| if(o.to_user === sshout_canoncal_user_name) return; |
| if(o.message_type !== "image") return; |
| var md5 = crypto.createHash("md5"); |
| md5.update(o.message); |
| //var file_path = util.format("%s/%s.jpg", image_dir, md5.digest("hex")); |
| var file_name = md5.digest("hex") + ".jpg"; |
| var file_path = image_dir + "/" + file_name; |
| var reply_message = util.format("%s's image: %s/%s", o.from_user, reply_url, file_name); |
| if(fs.existsSync(file_path)) sshout_client.send_message(o.to_user, "plain", reply_message); |
| else fs.writeFile(file_path, o.message, { mode:0644, flag:"wx" }, function(e) { |
| if(e) throw e; |
| sshout_client.send_message(o.to_user, "plain", reply_message); |
| }); |
| }); |
| |
| sshout_client.start(); |