'use strict'; var oauth3 = require('./oauth3.js'); var defaults = { main: 'oauth3' , provider: 'oauth3.org' }; function parseArgs(argv, opts) { var args = Array.prototype.slice.call(argv); var sep = /[:\.\-]/; args.shift(); // 'node' is the first parameter args.shift(); // 'oauth3.js' will be the var command = args.shift() || 'help'; var cmdpair = command.split(sep); var cmd = cmdpair[0]; var sub = cmdpair[1]; var COMMAND = 'COMMAND'; var maxCmdLen = COMMAND.length; var maxPairLen = 0; var arg1 = args[0]; // build top-level commands (tlcs) list // also count the word-width (for the space needed to print the commands) var pairsMap = {}; var tlcs = opts.commands.filter(function (desc) { var pair = desc[0].split(/\s+/)[0]; var psub = pair.split(sep)[0]; pairsMap[pair] = true; maxPairLen = Math.max(maxPairLen, pair.length); if (pair === psub) { maxCmdLen = Math.max(maxCmdLen, psub.length); return true; } }); // right pad (for making the printed lines longer) function rpad(str, len) { while (str.length < len) { str += ' '; } return str; } // oauth3.js help // oauth3.js help // oauth3.js help (alias of `oauth3.js --help') function help() { var status = 0; function printCmd(desc) { var pcmd = rpad(desc[0].split(/\s+/)[0], maxCmdLen); var pdesc = desc[1]; console.info('\t' + defaults.main + ' ' + pcmd, ' # ' + pdesc); } function printCmds(cmds) { console.info(''); var title = defaults.main + ' ' + rpad(COMMAND, maxCmdLen) + ' # description'; var bars = title.replace(/./g, '-').split(''); bars[bars.length - ' # description'.length] = ' '; bars[bars.length - (' # description'.length + 1)] = ' '; console.info('\t' + title); console.info('\t' + bars.join('')); cmds.forEach(printCmd); console.info(''); } function helpMain() { console.info(''); console.info('Here are all the top-level commands:'); printCmds(tlcs); } if (arg1 && -1 === Object.keys(pairsMap).indexOf(arg1)) { status = 1; console.info(''); console.info(defaults.main + ": Unknown command '" + arg1 + "'"); console.info(''); console.info("Try '" + defaults.main + " help'"); console.info(''); arg1 = null; return; } // the case of "oauth3 help --something" if (!arg1 || '-' === arg1[0]) { helpMain(); process.exit(status); return; } // the case of "oauth3 help help" if ('help' === arg1) { helpMain(); console.info("no more help available for 'help'"); process.exit(status); return; } // matches the first part of the command // and has second parts if (arg1 === arg1.split(':')[0] && opts.commands.filter(function (desc) { return arg1 === desc[0].split(/\s+/)[0].split(':')[0] && desc[0].split(/\s+/)[0].split(':'); }).length > 1) { console.info(''); console.info("Here are all the '" + command + "'-related commands:"); printCmds( opts.commands.filter(function (desc) { var pair = desc[0].split(/\s+/)[0]; var psub = pair.split(sep)[0]; maxPairLen = Math.max(maxPairLen, pair.length); if (arg1 === psub || arg1 === pair) { maxCmdLen = Math.max(maxCmdLen, pair.length); return true; } }) ); console.info(''); } else { console.info(''); console.info("Here are all the options and flags for '" + arg1 + "':"); console.info(''); opts.commands.some(function (desc) { var pair = desc[0].split(/\s+/)[0]; var psub = pair.split(sep)[0]; maxPairLen = Math.max(maxPairLen, pair.length); if (arg1 !== psub && arg1 !== pair) { return false; } maxCmdLen = Math.max(maxCmdLen, pair.length); console.log('\t' + desc[0] + '\t# ' + desc[1]); (desc[2]||[]).forEach(function (flag) { var pair = flag.split(', '); var f = pair.shift(); var d = pair.join(', '); console.log('\t\t' + f + ' # ' + d); }); return true; }); console.info(''); } } // If the command is not in the list of commands if (-1 === Object.keys(pairsMap).indexOf(cmd)) { arg1 = cmd; cmd = 'help'; help(); return; } // If help is explictly requested if (-1 !== [ 'help', '-h', '--help' ].indexOf(command) || -1 !== args.indexOf('-h') || -1 !== args.indexOf('--help')) { help(); return; } // If we're ready to rock and roll! console.log('RUN', cmd, sub || '(n/a)', arg1 || '(n/a)', '... not yet implemented'); } parseArgs(process.argv, { // CLI goals: // // whoami / login: you are now logged in as // * john@example.com [current] (just now) // * john@work.net (2 minutes ago) // * john@family.me (2 weeks ago) commands: [ [ 'login [email or cloud address]', 'alias of session:attach', [ "--auto, create a new account without asking if none exists" //, "--exclusive, logout all other ids, removing access to their accounts" , "--provider, specify an authentication provider (default: :provider)".replace(/\b:provider\b/, defaults.provider) //, "--email [addr], use the given id as an email address, even if it works as a cloud address" //, "--cloud [addr], use the given id as a cloud address or fail (don't fallback to email)" ] ] , [ 'logout', 'alias of session:detach' ] , [ 'whoami', 'show current account(s) and login(s) and device(s)' ] // authn , [ 'session', 'Manage your ids (credentials / logins)' ] , [ 'session:new', 'alias of `login --exclusive`' ] , [ 'session:attach', 'Create a session (and account if needed) for a given email address or cloud address' ] , [ 'session:detach', 'remove login from session' ] , [ 'session:list', 'show all of the ids in the current session' ] // authz , [ 'accounts', 'Manage your accounts (authorization / profiles)' ] , [ 'accounts:new', 'create a new account attached to the credentials of the current session' ] , [ 'accounts:set', 'change account details' ] // todo changing the name should be restricted john@provider.net -> jonathan@provider.net would be bad , [ 'accounts:list', 'show all of the accounts in the current session' ] , [ 'accounts:attach', 'attach an account to an id' ] , [ 'accounts:detach', 'detach an account from an id' ] , [ 'accounts:select', 'select an account to use as the primary account for this session' ] , [ 'accounts:update', '(deprecated) alias of set' ] , [ 'accounts:login', '(deprecated) alias of login' ] , [ 'accounts:whoami', '(deprecated) alias of whoami' ] // authn / authz , [ 'devices', 'manages devices for your account(s)' ] , [ 'devices:new', 'create a new device (default name is hostname, default ip is the result of :provider/api/tunnel@oauth3.org/checkip)'.replace(/\b:provider\b/, defaults.provider) ] , [ 'devices:set', 'set the ip address of the device (defaults ip is the result of :provider/api/tunnel@oauth3.org/checkip)'.replace(/\b:provider\b/, defaults.provider) ] , [ 'devices:attach', "attach a device to a domain's DNS record" ] , [ 'devices:detach', "detach an account from a domain's DNS record" ] , [ 'devices:select', '(re)claim the specified device as this device (i.e. you re-installed your OS or deleted your ~/.oauth3)' ] , [ 'devices:list', 'show all devices for your account(s)' ] // help , [ 'help', "show this menu; use '" + defaults.main + " help COMMAND' (even 'help') for options and sub-commands" ] ] });