Today I updated lesspass-cli on npm to fix an old issue in the counter. https://github.com/privacytoolsIO/privacytools.io/issues/679 Add this here for memory I will remove the folder in anoter commitpull/478/head
@@ -0,0 +1,80 @@ | |||
# LessPass cli | |||
LessPass passwords directly in your terminal | |||
## Install | |||
``` | |||
$ npm install --global lesspass-cli | |||
``` | |||
## Usage | |||
``` | |||
$ lesspass --help | |||
build LessPass passwords directly in command line | |||
Usage | |||
$ lesspass <site> <login> [masterPassword] [options] | |||
Options | |||
-l add lowercase in password | |||
-u add uppercase in password | |||
-d add digits in password | |||
-s add symbols in password | |||
--no-lowercase remove lowercase from password | |||
--no-uppercase remove uppercase from password | |||
--no-digits remove digits from password | |||
--no-symbols remove symbols from password | |||
--length, -L int (default 16) | |||
--counter, -c int (default 1) | |||
--clipboard, -C copy generated password to clipboard rather than displaying it. | |||
Need pbcopy (OSX), xclip (Linux) or clip (Windows). | |||
Examples | |||
# no symbols | |||
$ lesspass lesspass.com contact@lesspass.com password --no-symbols | |||
OlfK63bmUhqrGODR | |||
# no symbols shortcut | |||
$ lesspass lesspass.com contact@lesspass.com password -lud | |||
OlfK63bmUhqrGODR | |||
# only digits and length of 8 | |||
$ lesspass lesspass.com contact@lesspass.com -d -L8 | |||
master password: | |||
75837019 | |||
``` | |||
## FAQ | |||
### How can I generate a password if I have a quote (`'`) in my master password ? | |||
Escape the quote like this : | |||
lesspass lesspass.com contact@lesspass.com 'my parents'\'' house is great' | |||
Replace `'` by `'\''` | |||
### password prompt | |||
If you omit master password, lesspass-cli will ask you a master password: | |||
lesspass lesspass.com contact@lesspass.com --length=14 | |||
master password: | |||
## License | |||
This project is licensed under the terms of the GNU GPLv3. | |||
## Issues | |||
report issues on [LessPass project](https://github.com/lesspass/lesspass/issues) |
@@ -0,0 +1,145 @@ | |||
#!/usr/bin/env node | |||
"use strict"; | |||
const clipboardy = require("clipboardy"); | |||
const meow = require("meow"); | |||
const LessPass = require("lesspass"); | |||
const read = require("read"); | |||
const chalk = require("chalk"); | |||
const helpMessage = ` | |||
Usage | |||
$ lesspass <site> <login> [masterPassword] [options] | |||
Options | |||
-l add lowercase in password | |||
-u add uppercase in password | |||
-d add digits in password | |||
-s add symbols in password | |||
--no-lowercase remove lowercase from password | |||
--no-uppercase remove uppercase from password | |||
--no-digits remove digits from password | |||
--no-symbols remove symbols from password | |||
--length, -L int (default 16) | |||
--counter, -c int (default 1) | |||
--clipboard, -C copy generated password to clipboard rather than displaying it. | |||
Need pbcopy (OSX), xsel (Linux) or clip (Windows). | |||
Examples | |||
# no symbols | |||
$ lesspass lesspass.com contact@lesspass.com password --no-symbols | |||
OlfK63bmUhqrGODR | |||
# no symbols shortcut | |||
$ lesspass lesspass.com contact@lesspass.com password -lud | |||
OlfK63bmUhqrGODR | |||
# only digits and length of 8 | |||
$ lesspass lesspass.com contact@lesspass.com -d -L8 | |||
master password: | |||
75837019`; | |||
const cli = meow(helpMessage, { | |||
flags: { | |||
site: { type: "string" }, | |||
login: { type: "string" }, | |||
length: { | |||
inferType: true, | |||
alias: "L" | |||
}, | |||
counter: { | |||
inferType: true, | |||
alias: "c" | |||
}, | |||
clipboard: { | |||
type: "boolean", | |||
alias: "C" | |||
}, | |||
l: { type: "boolean" }, | |||
u: { type: "boolean" }, | |||
d: { type: "boolean" }, | |||
s: { type: "boolean" } | |||
} | |||
}); | |||
function calcPassword(site, login, masterPassword, passwordProfile) { | |||
LessPass.generatePassword(site, login, masterPassword, passwordProfile).then( | |||
function(generatedPassword) { | |||
if (passwordProfile.clipboard) { | |||
clipboardy | |||
.write(generatedPassword) | |||
.then(() => { | |||
console.log("Copied to clipboard"); | |||
process.exit(); | |||
}) | |||
.catch(err => { | |||
console.error(chalk.red("Copy failed.")); | |||
console.error(err.message); | |||
process.exit(1); | |||
}); | |||
} else { | |||
console.log(generatedPassword); | |||
process.exit(); | |||
} | |||
} | |||
); | |||
} | |||
function hasNoShortOption(options) { | |||
return !["l", "u", "d", "s"].some(function(shortOption) { | |||
return typeof options[shortOption] !== "undefined" && options[shortOption]; | |||
}); | |||
} | |||
function getOptionBoolean(options, optionString) { | |||
let shortOption = optionString.substring(0, 1); | |||
if (options[shortOption]) { | |||
return true; | |||
} | |||
if (typeof options[optionString] === "undefined") { | |||
return hasNoShortOption(options); | |||
} | |||
return options[optionString]; | |||
} | |||
const lowercase = getOptionBoolean(cli.flags, "lowercase"); | |||
const uppercase = getOptionBoolean(cli.flags, "uppercase"); | |||
const symbols = getOptionBoolean(cli.flags, "symbols"); | |||
const digits = getOptionBoolean(cli.flags, "digits"); | |||
const passwordProfile = { | |||
lowercase: lowercase, | |||
uppercase: uppercase, | |||
symbols: symbols, | |||
numbers: digits, | |||
clipboard: cli.flags.clipboard || false, | |||
length: cli.flags.length || 16, | |||
counter: cli.flags.counter || 1 | |||
}; | |||
const site = cli.input[0]; | |||
let login = cli.input[1]; | |||
if (typeof login === "undefined") { | |||
login = ""; | |||
} | |||
if (typeof site === "undefined") { | |||
console.log(chalk.red("site cannot be empty")); | |||
console.log("type lesspass --help"); | |||
process.exit(-1); | |||
} | |||
if (cli.input.length === 3) { | |||
const masterPassword = cli.input[2]; | |||
calcPassword(site, login, masterPassword, passwordProfile); | |||
} else { | |||
read({ prompt: "master password: ", silent: true }, function(er, password) { | |||
if (er && er.message === "canceled") { | |||
process.exit(); | |||
} | |||
calcPassword(site, login, password, passwordProfile); | |||
}); | |||
} |
@@ -0,0 +1,37 @@ | |||
{ | |||
"name": "lesspass-cli", | |||
"version": "5.2.0", | |||
"description": "build LessPass passwords directly in command line", | |||
"keywords": [ | |||
"cli", | |||
"cli-app", | |||
"lesspass", | |||
"password" | |||
], | |||
"license": "GPL-3.0", | |||
"author": "Guillaume Vincent <guillaume@oslab.fr>", | |||
"files": [ | |||
"cli.js" | |||
], | |||
"bin": { | |||
"lesspass": "cli.js" | |||
}, | |||
"repository": "lesspass/cli", | |||
"scripts": { | |||
"precommit": "npm test", | |||
"prepush": "npm test", | |||
"test": "ava" | |||
}, | |||
"dependencies": { | |||
"chalk": "2.3.1", | |||
"clipboardy": "1.2.3", | |||
"lesspass": "9.0.0", | |||
"meow": "4.0.0", | |||
"read": "1.0.7" | |||
}, | |||
"devDependencies": { | |||
"ava": "^0.25.0", | |||
"execa": "^0.9.0", | |||
"husky": "^0.14.3" | |||
} | |||
} |
@@ -0,0 +1,302 @@ | |||
import test from "ava"; | |||
import execa from "execa"; | |||
test("default options", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "\\g-A1-.OHEwrXjT#"); | |||
}); | |||
test("no login", async t => { | |||
return execa.shell('echo password | ./cli.js "lesspass.com"').then(result => { | |||
t.is(result.stdout, "master password: 7Cw-APO5Co?G>W>u"); | |||
}); | |||
}); | |||
test("options can be before parameters", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"-C", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "Copied to clipboard"); | |||
}); | |||
test("long options can be before parameters", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"--clipboard", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "Copied to clipboard"); | |||
}); | |||
test("length", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--length=14" | |||
]); | |||
t.is(stdout, "=0\\A-.OHEKvwrX"); | |||
}); | |||
test("length shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-L=14" | |||
]); | |||
t.is(stdout, "=0\\A-.OHEKvwrX"); | |||
}); | |||
test("counter", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--counter=2" | |||
]); | |||
t.is(stdout, "Vf:F1'!I`8Y2`GBE"); | |||
}); | |||
test("counter shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-c=2" | |||
]); | |||
t.is(stdout, "Vf:F1'!I`8Y2`GBE"); | |||
}); | |||
test("counter nrt", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--counter=10" | |||
]); | |||
t.is(stdout, "qwv0l*n?i^Q745\\w"); | |||
}); | |||
test("no lowercase", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--no-lowercase" | |||
]); | |||
t.is(stdout, 'JBG\\`3{+0["(E\\JJ'); | |||
}); | |||
test("no lowercase shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-uds" | |||
]); | |||
t.is(stdout, 'JBG\\`3{+0["(E\\JJ'); | |||
}); | |||
test("only lowercase", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-l" | |||
]); | |||
t.is(stdout, "fmnujoqgcxmpffyh"); | |||
}); | |||
test("no uppercase", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--no-uppercase" | |||
]); | |||
t.is(stdout, 'jbg\\`3{+0["(e\\jj'); | |||
}); | |||
test("no uppercase shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-lds" | |||
]); | |||
t.is(stdout, 'jbg\\`3{+0["(e\\jj'); | |||
}); | |||
test("only uppercase", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-u" | |||
]); | |||
t.is(stdout, "FMNUJOQGCXMPFFYH"); | |||
}); | |||
test("no digits", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--no-digits" | |||
]); | |||
t.is(stdout, ";zkB#m]mNF$;J_Ej"); | |||
}); | |||
test("no digits shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-lus" | |||
]); | |||
t.is(stdout, ";zkB#m]mNF$;J_Ej"); | |||
}); | |||
test("only digits", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-d" | |||
]); | |||
t.is(stdout, "7587019305478072"); | |||
}); | |||
test("no symbols", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--no-symbols" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("no symbols shortcut", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-lud" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("only symbols", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-s" | |||
]); | |||
t.is(stdout, "<\"]|'`%};'`>-'[,"); | |||
}); | |||
test("test space in password", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"my Master Password" | |||
]); | |||
t.is(stdout, "D1PBB34\\#fh!LY={"); | |||
}); | |||
test("doc 1", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"--no-symbols" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("doc 1 options before", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"--no-symbols", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("doc 2", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-lud" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("doc 2 options before", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"-lud", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "OlfK63bmUhqrGODR"); | |||
}); | |||
test("doc 3", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-d", | |||
"-L8" | |||
]); | |||
t.is(stdout, "75837019"); | |||
}); | |||
test("doc 3 options before", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"-d", | |||
"-L8", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password" | |||
]); | |||
t.is(stdout, "75837019"); | |||
}); | |||
test("doc 3 options before and after", async t => { | |||
const { stdout } = await execa("./cli.js", [ | |||
"-d", | |||
"lesspass.com", | |||
"contact@lesspass.com", | |||
"password", | |||
"-L8" | |||
]); | |||
t.is(stdout, "75837019"); | |||
}); | |||
test("nrt numbers should be considered as string not integers", async t => { | |||
const p = execa("./cli.js", ["example.org", "123", "password"]); | |||
const p2 = execa("./cli.js", ["example.org", "0123", "password"]); | |||
const p3 = execa("./cli.js", ["example.org", '"0123"', "password"]); | |||
const p4 = execa("./cli.js", ["example.org", "00123", "password"]); | |||
return Promise.all([p, p2, p3, p4]).then(v => { | |||
t.is(v[0].stdout, "sMb8}N&`J4wkF9q~"); | |||
t.is(v[1].stdout, "5,4SqhB2[=/h\\DZh"); | |||
t.is(v[2].stdout, "u0Fz)EOJ4i\\{{;a~"); | |||
t.is(v[3].stdout, '=}|O7hN0ZHdjQ{">'); | |||
}); | |||
}); |