Skip to content

Commit

Permalink
feat: List last 5 pushed password
Browse files Browse the repository at this point in the history
  • Loading branch information
leandrof-ciandt authored and lnfnunes committed Apr 10, 2018
1 parent ca013da commit 51349a0
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 30 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ language: node_js
node_js:
- 'node'
- '8'
- '6'
cache:
directories:
- node_modules
Expand Down
60 changes: 45 additions & 15 deletions __tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ const pwpush = require('../lib/pwpush')

const DEFAULT_EXPIRE_DAYS = '7'
const DEFAULT_EXPIRE_VIEWS = '5'
const DEFAULT_LAST_ITEMS = '5'
const HOST = 'https://pwpush.com'
const PERMALINK = `${HOST}/p`

axios.defaults.host = HOST;
axios.defaults.adapter = httpAdapter;
axios.defaults.host = HOST
axios.defaults.adapter = httpAdapter

const objDefault = {
password: 'MyVerySecretP@sswd2BeBroken',
Expand All @@ -33,6 +34,9 @@ const mockRequest = (json) => {
return api
}

beforeEach(() => {
pwpush.clearHistory()
})
afterEach(() => {
nock.cleanAll()
})
Expand All @@ -45,38 +49,38 @@ test(`Should throw an Error with message "A password is required!" if password w
})
})
.toThrowError(`A password is required!`)
});
})
test(`Should throw an Error with message "The password is too weak!" if password don't pass the OWASP test`, () => {
expect(() => {
pwpush({
password: 'weakP@ssword'
})
})
.toThrowError(`The password is too weak!`)
});
})
test(`Should throw an Error with message containing security issues about OWASP test requirements`, () => {
expect(() => {
pwpush({
password: 'p@ssw0rd'
})
})
.toThrowError(`The password must be at least 10 characters long`)
});
})
test(`Should throw an Error with message containing a link to OWASP security guideline`, () => {
expect(() => {
pwpush({
password: 'p@ssw0rd'
})
})
.toThrowError(`https://bit.ly/owasp-secure-guideline`)
});
})

test(`Should have ${objDefault.expire_days} as default value for --days flag`, () => {
expect(DEFAULT_EXPIRE_DAYS).toBe(objDefault.expire_days);
});
expect(DEFAULT_EXPIRE_DAYS).toBe(objDefault.expire_days)
})
test(`Should have ${objDefault.expire_views} as default value for --views flag`, () => {
expect(DEFAULT_EXPIRE_VIEWS).toBe(objDefault.expire_views);
});
expect(DEFAULT_EXPIRE_VIEWS).toBe(objDefault.expire_views)
})
test(`Should allow weak password if --allow-weak flag is set`, () => {
expect(() => {
pwpush(Object.assign({}, objDefault, {
Expand All @@ -85,7 +89,7 @@ test(`Should allow weak password if --allow-weak flag is set`, () => {
}))
})
.not.toThrow()
});
})

test(`Should call pwpush.com with default request parameters`, (done) => {
mockRequest(responseValid)
Expand All @@ -103,7 +107,7 @@ test(`Should call pwpush.com with default request parameters`, (done) => {
expect(result).toEqual(expected)
done()
})
});
})
test(`Should call pwpush.com API with custom request parameters`, (done) => {
mockRequest(responseValid)

Expand All @@ -125,7 +129,7 @@ test(`Should call pwpush.com API with custom request parameters`, (done) => {
expect(result).toEqual(expected)
done()
})
});
})
test(`Should return an text message with "${PERMALINK}/${responseValid.url_token}" when response is valid`, (done) => {
mockRequest(responseValid)

Expand All @@ -140,7 +144,7 @@ test(`Should return an text message with "${PERMALINK}/${responseValid.url_token
expect(res.text).toContain(`${PERMALINK}/${responseValid.url_token}`)
done()
})
});
})
test(`Should reject the promise with Error containing message "Something gets wrong!!" when response is invalid`, (done) => {
mockRequest(responseInvalid)

Expand All @@ -149,4 +153,30 @@ test(`Should reject the promise with Error containing message "Something gets wr
expect(err).toEqual(Error(`Something gets wrong!!`))
done()
})
});
})

test(`Should clear the list of pushed passwords`, async () => {
pwpush.clearHistory()

const result = pwpush.showHistory().split('')
const expected = 0
expect(result).toHaveLength(expected)
})
test(`Should show a list of pushed password urls when --list flag is set`, async () => {
const max = parseInt(DEFAULT_LAST_ITEMS, 10)
for (let i=1; i<=max; i++) {
mockRequest(responseValid)
await pwpush({password: objDefault.password})

expect(pwpush.showHistory().split('\n')).toHaveLength(i)
}
})
test(`Should show a list with no more than ${DEFAULT_LAST_ITEMS} pushed password items`, async () => {
const max = parseInt(DEFAULT_LAST_ITEMS, 10)
for (let i=1; i<=max + 1; i++) {
mockRequest(responseValid)
await pwpush({password: objDefault.password})
}

expect(pwpush.showHistory().split('\n')).toHaveLength(max)
})
10 changes: 8 additions & 2 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const showHelp = (txt = '\r') => {
\r $ pwpush <password> [parameters] [options]
\rParameters
\r --days | -d Days until the password is deleted. Default is ${pwpush.DEFAULT_EXPIRE_DAYS}
\r --days | -d Days until the password is deleted. Default is ${pwpush.DEFAULT_EXPIRE_DAYS}
\r --views | -v Number of visualizations until the password is deleted. Default is ${pwpush.DEFAULT_EXPIRE_VIEWS}
\r --list | -l List last ${pwpush.DEFAULT_LAST_ITEMS} pushed passwords.
\rOptions
\r --allow-weak Allow weak passwords to be used.
Expand All @@ -26,10 +27,11 @@ const showHelp = (txt = '\r') => {
}

const cli = parseArgs(process.argv.slice(2), {
boolean: ['version', 'help', 'allow-weak'],
boolean: ['version', 'help', 'allow-weak', 'list'],
alias: {
d: 'days',
v: 'views',
l: 'list',
h: 'help',
},
unknown: (value) => {
Expand All @@ -46,6 +48,10 @@ if (!!cli.version) {
if (!!cli.help || !cli._[0]) {
showHelp()
}
if (!!cli.list) {
console.log(pwpush.showHistory())
process.exit(0)
}

const spinner = ora().start()

Expand Down
59 changes: 51 additions & 8 deletions lib/pwpush.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,84 @@
const axios = require('axios')
const clip = require('node-clipboard')
const owasp = require('owasp-password-strength-test')
const storage = require('user-settings').file('.pwpushcli');
const querystring = require('querystring')

const DEFAULT_EXPIRE_DAYS = '7'
const DEFAULT_EXPIRE_VIEWS = '5'
const DEFAULT_LAST_ITEMS = '5'
const HOST = 'https://pwpush.com'
const PERMALINK = `${HOST}/p`

const onResponseComplete = (response) => {
const onApiResponseComplete = (response) => {
const json = response.data

if( !json.url_token || !json.expire_after_days || !json.expire_after_views) {
throw new Error(`Something gets wrong!!`)
}

const url = getUrlValue(json)

clip(url)
setHistory(url, json)

return {
_: response,
text: getResultText(json),
text: getResultText(url, json),
}
}

const getResultText = (json) => {
const url = getUrlValue(json)
clip(url)

const getResultText = (url, json) => {
return ` ${url}
\r=> ${getExpirationDate(json)}`
}

const getUrlValue = ({url_token}) => `${PERMALINK}/${url_token}`
const getExpirationDate = ({expire_after_days, expire_after_views}) => (
`This secret link will be deleted in ${expire_after_days} day or ${expire_after_views} more views`
)

const clearHistory = () => {
storage.unset('history')
}
const showHistory = () => {
return getHistory()
.map((item) => `- [${formatDate(item.date)}] ${item.url} (days ${item.days}, views ${item.views})`)
.join('\n')
}
const getHistory = () => []
.concat(storage.get('history'))
.filter(item => !!item)

const setHistory = (url, {expire_after_days, expire_after_views}) => {
storage.set('history', [
{
date: Date.now(),
url: url,
days: expire_after_days,
views: expire_after_views,
}]
.concat(getHistory())
.slice(0, DEFAULT_LAST_ITEMS)
)
}

const formatDate = (date) => {
const d = new Date(date)
const strDate = `${d.toLocaleDateString(undefined, {
year: 'numeric',
month: '2-digit',
day: '2-digit'
})}`

return strDate
}

module.exports = ({
password,
expire_days = DEFAULT_EXPIRE_DAYS,
expire_views = DEFAULT_EXPIRE_VIEWS,
allow_weak = false,
showHistory
}) => {
if (!password) {
throw new Error(`A password is required!`)
Expand Down Expand Up @@ -68,5 +108,8 @@ module.exports = ({
}

return axios(reqOptions)
.then(onResponseComplete)
.then(onApiResponseComplete)
}

module.exports.clearHistory = clearHistory
module.exports.showHistory = showHistory
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pwpush-cli",
"description": "A nodeJS CLI wrapper to easily push passwords to pwpush.com",
"version": "0.6.1",
"version": "0.7.0",
"author": {
"name": "Leandro Nunes",
"email": "[email protected]",
Expand Down Expand Up @@ -33,7 +33,7 @@
},
"main": "cli.js",
"engines": {
"node": ">=6"
"node": ">=8"
},
"scripts": {
"prepublish": "npm test",
Expand All @@ -50,7 +50,8 @@
"minimist": "^1.2.0",
"node-clipboard": "^1.2.0",
"ora": "^2.0.0",
"owasp-password-strength-test": "^1.3.0"
"owasp-password-strength-test": "^1.3.0",
"user-settings": "^0.2.0"
},
"devDependencies": {
"coveralls": "^3.0.0",
Expand Down

0 comments on commit 51349a0

Please sign in to comment.