dnt-connect
Advanced tools
Comparing version 1.0.1 to 2.0.0
// Generated by CoffeeScript 1.6.3 | ||
var Connect, crypto; | ||
var CONNECT_URL, Connect, crypto; | ||
crypto = require('crypto'); | ||
CONNECT_URL = 'https://www.turistforeningen.no/connect'; | ||
/* | ||
# | ||
# Create DNT Connect client | ||
# | ||
# @param <string-utf8> client - DNT Connect client name | ||
# @param <string-base64> key - DNT Connect API key | ||
# @param <object> opts - options | ||
# | ||
# @return <Connect> class instance | ||
# | ||
*/ | ||
Connect = function(client, key, opts) { | ||
@@ -18,33 +33,181 @@ if (!client) { | ||
Connect.prototype.encrypt = function(plaintext) { | ||
var cipher; | ||
cipher = crypto.createCipheriv('aes-256-ecb', this.key, ''); | ||
return cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64'); | ||
/* | ||
# | ||
# Generate hmac of plaintext and iv | ||
# | ||
# @param <string-utf8> plaintext - plaintext to encipher | ||
# @param <Buffer> iv - initialization vector | ||
# | ||
# @return <string-base64> of hmac | ||
# | ||
*/ | ||
Connect.prototype.hmacPlaintext = function(plaintext, iv) { | ||
var hmac; | ||
hmac = crypto.createHmac('sha512', this.key); | ||
hmac.update(Buffer.concat([iv, new Buffer(plaintext, 'utf8')])); | ||
return hmac.digest('base64'); | ||
}; | ||
Connect.prototype.decrypt = function(ciphertext) { | ||
/* | ||
# | ||
# Verify hmac of plaintext is correct | ||
# | ||
# @param <string-utf8> plaintext - plaintext to encipher | ||
# @param <Buffer> iv - initialization vector | ||
# @param <string-base64> hmac - hmac of plaintext | ||
# | ||
# @return {@code true} if hmac is valid; otherwise {@code false} | ||
# | ||
*/ | ||
Connect.prototype.verifyPlaintext = function(plaintext, iv, hmac) { | ||
return this.hmacPlaintext(plaintext, iv) === hmac; | ||
}; | ||
/* | ||
# | ||
# Encipher plaintext and prepend iv | ||
# | ||
# @param <string-utf8> plaintext - plaintext to encipher | ||
# @param <Buffer> iv - initialization vector | ||
# | ||
# @return <string-base64> of the iv prepended to the ciphertext | ||
# | ||
*/ | ||
Connect.prototype.encryptPlaintext = function(plaintext, iv) { | ||
var buffers, cipher; | ||
cipher = crypto.createCipheriv('aes-256-cbc', this.key, iv); | ||
buffers = [iv, cipher.update(plaintext, 'utf8'), cipher.final()]; | ||
return Buffer.concat(buffers).toString('base64'); | ||
}; | ||
/* | ||
# | ||
# Decipher ciphertext | ||
# | ||
# @param <Buffer> ciphertext - ciphertext to decipher | ||
# @param <Buffer> iv - initialization vector | ||
# | ||
# @return <string-utf8> with plaintext | ||
# | ||
*/ | ||
Connect.prototype.decryptCiphertext = function(ciphertext, iv) { | ||
var cipher; | ||
cipher = crypto.createDecipheriv('aes-256-ecb', this.key, ''); | ||
return cipher.update(ciphertext, 'base64', 'utf8') + cipher.final('utf8'); | ||
cipher = crypto.createDecipheriv('aes-256-cbc', this.key, iv); | ||
return cipher.update(ciphertext, '', 'utf8') + cipher.final('utf8'); | ||
}; | ||
Connect.prototype.decryptJSON = function(uriEncodedCiphertext) { | ||
return JSON.parse(this.decrypt(decodeURIComponent(uriEncodedCiphertext))); | ||
/* | ||
# | ||
# Encrypt plaintext and hmac it | ||
# | ||
# @param <string-utf8> plaintext - plaintext to encipher | ||
# @param <Buffer> iv - initialization vector | ||
# | ||
# @return <Array> with <string-base64> ciphertext and <string-base64> hmac | ||
# | ||
*/ | ||
Connect.prototype.encryptAndHash = function(plaintext, iv) { | ||
return [this.encryptPlaintext(plaintext, iv), this.hmacPlaintext(plaintext, iv)]; | ||
}; | ||
Connect.prototype.encryptJSON = function(json) { | ||
return encodeURIComponent(this.encrypt(JSON.stringify(json))); | ||
/* | ||
# | ||
# Decrypt ciphertext and verify hmac | ||
# | ||
# @param <string-base64> ciphertext - ciphertext to decipher | ||
# @param <string-base64> hmac - hmac of plaintext and iv | ||
# | ||
# @return <Array> with <string-utf8> plaintext and <boolean> verification | ||
# | ||
*/ | ||
Connect.prototype.decryptAndVerify = function(ciphertext, hmac) { | ||
var iv, pt; | ||
ciphertext = new Buffer(ciphertext, 'base64'); | ||
iv = ciphertext.slice(0, 16); | ||
pt = this.decryptCiphertext(ciphertext.slice(16), iv); | ||
return [pt, this.verifyPlaintext(pt, iv, hmac)]; | ||
}; | ||
Connect.prototype.getPayload = function(redirectUrl) { | ||
return { | ||
redirect_url: redirectUrl, | ||
timestamp: Math.floor(new Date().getTime() / 1000) | ||
}; | ||
/* | ||
# | ||
# Decrypt encrypted data from DNT Connect | ||
# | ||
# @param <string-base64> data - encrypted data | ||
# @param <string-base64> hmac - hmaced data verification | ||
# | ||
# @return <Array> with <object> decrypted data and <boolean> verification | ||
# | ||
*/ | ||
Connect.prototype.decryptJSON = function(data, hmac) { | ||
var json, valid, _ref; | ||
data = decodeURIComponent(data); | ||
hmac = decodeURIComponent(hmac); | ||
_ref = this.decryptAndVerify(data, hmac), json = _ref[0], valid = _ref[1]; | ||
return [JSON.parse(json), valid]; | ||
}; | ||
/* | ||
# | ||
# Encrypt JSON and return ciphertext and hmac | ||
# | ||
# @param <object> json - json data to encrypt | ||
# @param <Buffer> iv - initialization vector | ||
# | ||
# @return <Array> with <string-base64> ciphertext and <string-base64> hmac | ||
# | ||
*/ | ||
Connect.prototype.encryptJSON = function(json, iv) { | ||
var cipher, hmac, _ref; | ||
_ref = this.encryptAndHash(JSON.stringify(json), iv), cipher = _ref[0], hmac = _ref[1]; | ||
return [encodeURIComponent(cipher), encodeURIComponent(hmac)]; | ||
}; | ||
/* | ||
# | ||
# Get DNT Connect url for service type | ||
# | ||
# @param <string-utf8> type - authentication type | ||
# @param <string-utf8> redirectUrl - url to redirect user back to | ||
# | ||
# @return <string-utf8> url to DNT Connect | ||
# | ||
*/ | ||
Connect.prototype.getUrl = function(type, redirectUrl) { | ||
return ['https://www.turistforeningen.no/connect/', type, '/?client=', this.client, '&data=', this.encryptJSON(this.getPayload(redirectUrl))].join(''); | ||
var data, hmac, iv, _ref; | ||
_ref = this.encryptJSON({ | ||
redirect_url: redirectUrl, | ||
timestamp: Math.floor(new Date().getTime() / 1000) | ||
}, iv = crypto.randomBytes(16)), data = _ref[0], hmac = _ref[1]; | ||
return "" + CONNECT_URL + "/" + type + "/?client=" + this.client + "&data=" + data + "&hmac=" + hmac; | ||
}; | ||
/* | ||
# | ||
# Bounce user to DNT Connect to check authentication | ||
# | ||
# @param <string-utf8> redirectUrl - url to redirect user back to | ||
# | ||
# @return <string-utf8> url to DNT Connect | ||
# | ||
*/ | ||
Connect.prototype.bounce = function(redirectUrl) { | ||
@@ -54,2 +217,13 @@ return this.getUrl('bounce', redirectUrl); | ||
/* | ||
# | ||
# Make user sign on using DNT Connect | ||
# | ||
# @param <string-utf8> redirectUrl - url to redirect user back to | ||
# | ||
# @return <string-utf8> url to DNT Connect | ||
# | ||
*/ | ||
Connect.prototype.signon = function(redirectUrl) { | ||
@@ -59,2 +233,23 @@ return this.getUrl('signon', redirectUrl); | ||
/* | ||
# | ||
# Decrypt DNT Connect data | ||
# | ||
# @param <object> query - query parameters from DNT Connect | ||
# | ||
# @return <Array> with <object> decrypted data and <boolean> verification | ||
# | ||
*/ | ||
Connect.prototype.decrypt = function(query) { | ||
if ((query != null ? query.data : void 0) === void 0) { | ||
throw new Error('Param query.data is not defined'); | ||
} | ||
if ((query != null ? query.hmac : void 0) === void 0) { | ||
throw new Error('Param query.hmac is not defiend'); | ||
} | ||
return this.decryptJSON(query.data, query.hmac); | ||
}; | ||
module.exports = Connect; |
{ | ||
"name": "dnt-connect", | ||
"version": "1.0.1", | ||
"version": "2.0.0", | ||
"description": "Node.JS library for DNT's single sign on service DNT Connect", | ||
@@ -5,0 +5,0 @@ "main": "lib/dnt-connect.js", |
DNT Connect ![Build Status](https://drone.io/github.com/Turistforeningen/node-dnt-connect/status.png) | ||
=========== | ||
Node.JS library for DNT's single sign on service DNT Connect | ||
Node.JS library for DNT's single sign on service – DNT Connect | ||
## Requires | ||
## Requirements | ||
@@ -18,7 +18,9 @@ Require Node.JS version `>= 0.10`. | ||
```javascript | ||
var Connect = require('dnt-connect'); | ||
``` | ||
### New Client | ||
```javascript | ||
var Connect = require('dnt-connect'); | ||
var client = new Connect('myClientName', 'mySecretKey'); | ||
@@ -47,9 +49,25 @@ ``` | ||
### Decrypt Response Data | ||
### Decrypt Response | ||
All data sent and recieved is encrypted. In order to read the data you need to | ||
call `#decrypt()` wich will use your key to decrypt the data. | ||
All data sent and recieved to and from DNT Connect is encrypted by 256 bit AES cipher in CBC mode. | ||
In order to read recieved data from DNT Connect your application needs to call `#decrypt()` wich | ||
will use your privat DNT Connect API key to decrypt and verify the data. | ||
`NB` The return from the #decrypt() method is an `Array` with two elements in it; `data` and | ||
`valid`. The reason for this is because of [Destructing | ||
assignments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.7#Destructuring_assignment_(Merge_into_own_page.2Fsection)), | ||
new in ECMAScript 6. | ||
```javascript | ||
var data = client.decryptJSON(encryptedData); | ||
try { | ||
var data = client.decrypt({data: queryData, hmac: queryHmac}); | ||
if (data[1] is false) { | ||
console.log('Validation failed'); | ||
} else { | ||
console.log('Decrypted data'); | ||
console.log(data[0]); | ||
} | ||
} catch (e) { | ||
// Decryption or serialization failed | ||
} | ||
``` | ||
@@ -56,0 +74,0 @@ |
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
11313
7
210
93