@phc/format
Advanced tools
Comparing version 0.3.5 to 0.4.0
90
index.js
@@ -10,2 +10,4 @@ /* eslint-disable max-params,capitalized-comments,complexity */ | ||
const b64Regex = /^([a-zA-Z0-9/+.-]+|)$/; | ||
const degimalRegex = /(?<=\s|^)[-+]?\d+(?=\s|$)/; | ||
const versionRegex = /^v=(\d+)$/; | ||
@@ -38,5 +40,2 @@ function objToKeyVal(obj) { | ||
} | ||
function isNumeric(n) { | ||
return !isNaN(parseFloat(n)) && isFinite(n); | ||
} | ||
@@ -48,4 +47,3 @@ /** | ||
* @param {string} opts.id Symbolic name for the function. | ||
* @param {string} [opts.raw] Additional raw data added after the identifier. | ||
* It's here to support argon2 v parameter and to generate MCF formatted strings. | ||
* @param {Number} [opts.version] The version of the function. | ||
* @param {Object} [opts.params] Parameters of the function. | ||
@@ -72,9 +70,15 @@ * @param {Buffer} [opts.salt] The salt as a binary buffer. | ||
// This is to make argon2 format compatible | ||
if (typeof opts.raw === 'string') { | ||
fields.push(opts.raw); | ||
if (typeof opts.version !== 'undefined') { | ||
if ( | ||
typeof opts.version !== 'number' || | ||
opts.version < 0 || | ||
!Number.isInteger(opts.version) | ||
) { | ||
throw new TypeError('version must be a positive integer number'); | ||
} | ||
fields.push(`v=${opts.version}`); | ||
} | ||
// Parameters Validation | ||
if (typeof opts.params !== 'undefined') { | ||
if (typeof opts.params !== 'undefined' && typeof opts.raw === 'undefined') { | ||
if (typeof opts.params !== 'object' || opts.params === null) { | ||
@@ -130,12 +134,5 @@ throw new TypeError('params must be an object'); | ||
* @param {string} phcstr A PHC string to parse. | ||
* @param {boolean} [strict=true] If false does not throw an error if there is | ||
* one filed not unrecognized. The content of the unrecognized filed will be | ||
* stored in the raw property of the output object. This is useful to parse | ||
* out of specs parameters like the 'v' present in the argon2 hash format or | ||
* to parse MCF formatted strings. | ||
* @return {Object} The object containing the data parsed from the PHC string. | ||
*/ | ||
function deserialize(phcstr, strict) { | ||
strict = strict !== false; | ||
function deserialize(phcstr) { | ||
if (typeof phcstr !== 'string' || phcstr === '') { | ||
@@ -153,3 +150,3 @@ throw new TypeError('pchstr must be a non-empty string'); | ||
let maxf = 5; | ||
if (strict) maxf--; | ||
if (!versionRegex.test(fields[1])) maxf--; | ||
if (fields.length > maxf) { | ||
@@ -167,2 +164,8 @@ throw new TypeError( | ||
let version; | ||
// Parse Version | ||
if (versionRegex.test(fields[0])) { | ||
version = parseInt(fields.shift().match(versionRegex)[1], 10); | ||
} | ||
let hash; | ||
@@ -186,42 +189,21 @@ let salt; | ||
const parstr = fields.pop(); | ||
let isKeyVal = false; | ||
try { | ||
params = keyValtoObj(parstr); | ||
isKeyVal = true; | ||
} catch (err) { | ||
if (strict) { | ||
throw err; | ||
} | ||
fields.push(parstr); | ||
params = keyValtoObj(parstr); | ||
if (!objectKeys(params).every(p => nameRegex.test(p))) { | ||
throw new TypeError(`params names must satisfy ${nameRegex}`); | ||
} | ||
if (isKeyVal) { | ||
if (!objectKeys(params).every(p => nameRegex.test(p))) { | ||
throw new TypeError(`params names must satisfy ${nameRegex}`); | ||
} | ||
const pv = objectValues(params); | ||
if (!pv.every(v => valueRegex.test(v))) { | ||
throw new TypeError(`params values must satisfy ${valueRegex}`); | ||
} | ||
const pk = objectKeys(params); | ||
// Convert Numeric Strings into Numbers | ||
pk.forEach(k => { | ||
params[k] = isNumeric(params[k]) ? parseFloat(params[k]) : params[k]; | ||
}); | ||
const pv = objectValues(params); | ||
if (!pv.every(v => valueRegex.test(v))) { | ||
throw new TypeError(`params values must satisfy ${valueRegex}`); | ||
} | ||
const pk = objectKeys(params); | ||
// Convert Decimal Strings into Numbers | ||
pk.forEach(k => { | ||
params[k] = degimalRegex.test(params[k]) | ||
? parseInt(params[k], 10) | ||
: params[k]; | ||
}); | ||
} | ||
// Parse Raw Data if not in strict mode | ||
let raw; | ||
if (fields.length > 0) { | ||
if (strict) { | ||
throw new TypeError( | ||
`pchstr contains unrecognized fileds: ${fields.length}/0` | ||
); | ||
} | ||
if (fields.length !== 1) { | ||
throw new TypeError( | ||
`pchstr contains too many unrecognized fileds: ${fields.length}/1` | ||
); | ||
} | ||
raw = fields.pop(); | ||
throw new TypeError(`pchstr contains unrecognized fileds: ${fields}`); | ||
} | ||
@@ -231,6 +213,6 @@ | ||
const phcobj = {id}; | ||
if (version) phcobj.version = version; | ||
if (params) phcobj.params = params; | ||
if (salt) phcobj.salt = salt; | ||
if (hash) phcobj.hash = hash; | ||
if (raw) phcobj.raw = raw; | ||
@@ -237,0 +219,0 @@ return phcobj; |
{ | ||
"name": "@phc/format", | ||
"version": "0.3.5", | ||
"version": "0.4.0", | ||
"description": "PHC string format serializer/deserializer", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -105,7 +105,4 @@ <h1 align="center"> | ||
You can also pass an optional version parameter. | ||
Using the `raw` and `strict` parameters you can even serialize/deserialize | ||
PHC strings that does not strictly adhere to the 'standard', like the one | ||
used by [argon2](https://github.com/P-H-C/phc-winner-argon2/issues/157) | ||
```js | ||
@@ -116,3 +113,3 @@ const phc = require('@phc/format'); | ||
id: 'argon2i', | ||
raw: 'v=19', ← Note the v parameter | ||
version: 19, | ||
params: { | ||
@@ -126,3 +123,3 @@ m: 120, | ||
}; | ||
↓ Note the v parameter | ||
const phcstr = "$argon2i$v=19$m=120,t=5000,p=2$iHSDPHzUhPzK7rCcJgOFfg$J4moa2MM0/6uf3HbY2Tf5Fux8JIBTwIhmhxGRbsY14qhTltQt+Vw3b7tcJNEbk8ium8AQfZeD4tabCnNqfkD1g"; | ||
@@ -134,33 +131,5 @@ | ||
phc.deserialize(phcstr); | ||
// => throws an error since there are more than 4 fields (a field is one $) | ||
phc.deserialize(phcstr, false); | ||
// => phcobj | ||
``` | ||
With the same philosophy you can even serialize/deserialize MCF formatted strings. | ||
```js | ||
const phc = require('@phc/format'); | ||
const phcobj = { | ||
id: 'pbkdf2-sha256', | ||
raw: '6400', | ||
salt: Buffer.from('0ZrzXitFSGltTQnBWOsdAw', 'base64'), | ||
hash: Buffer.from('Y11AchqV4b0sUisdZd0Xr97KWoymNE0LNNrnEgY4H9M', 'base64'), | ||
}; | ||
const phcstr = "$pbkdf2-sha256$6400$0ZrzXitFSGltTQnBWOsdAw$Y11AchqV4b0sUisdZd0Xr97KWoymNE0LNNrnEgY4H9M"; | ||
phc.serialize(phcobj); | ||
// => phcstr | ||
phc.deserialize(phcstr); | ||
// => throws an error since the second field (a field is one $) is not a valid | ||
// params string | ||
phc.deserialize(phcstr, false); | ||
// => phcobj | ||
``` | ||
## API | ||
@@ -173,3 +142,3 @@ | ||
</dd> | ||
<dt><a href="#deserialize">deserialize(phcstr, [strict])</a> ⇒ <code>Object</code></dt> | ||
<dt><a href="#deserialize">deserialize(phcstr)</a> ⇒ <code>Object</code></dt> | ||
<dd><p>Parses data from a PHC string.</p> | ||
@@ -191,3 +160,3 @@ </dd> | ||
| opts.id | <code>string</code> | Symbolic name for the function. | | ||
| [opts.raw] | <code>string</code> | Additional raw data added after the identifier. It's here to support argon2 v parameter and to generate MCF formatted strings. | | ||
| [opts.version] | <code>Number</code> | The version of the function. | | ||
| [opts.params] | <code>Object</code> | Parameters of the function. | | ||
@@ -199,3 +168,3 @@ | [opts.salt] | <code>Buffer</code> | The salt as a binary buffer. | | ||
### deserialize(phcstr, [strict]) ⇒ <code>Object</code> | ||
### deserialize(phcstr) ⇒ <code>Object</code> | ||
Parses data from a PHC string. | ||
@@ -206,8 +175,6 @@ | ||
| Param | Type | Default | Description | | ||
| --- | --- | --- | --- | | ||
| phcstr | <code>string</code> | | A PHC string to parse. | | ||
| [strict] | <code>boolean</code> | <code>true</code> | If false does not throw an error if there is one filed not unrecognized. The content of the unrecognized filed will be stored in the raw property of the output object. This is useful to parse out of specs parameters like the 'v' present in the argon2 hash format or to parse MCF formatted strings. | | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| phcstr | <code>string</code> | A PHC string to parse. | | ||
## Contributing | ||
@@ -214,0 +181,0 @@ Contributions are REALLY welcome and if you find a security flaw in this code, PLEASE [report it][new issue]. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15336
194
198