forked from steemit/crypto-session
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
91 lines (77 loc) · 2.82 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
'use strict'
const sodium = require('libsodium-wrappers')
const session = require('koa-session')
module.exports = function(app, opts) {
opts = opts || {}
if (opts.signed === undefined) {
opts.signed = true
}
let secret
try {
secret = new Buffer(opts.crypto_key, 'base64')
if(secret.length !== sodium.crypto_secretbox_KEYBYTES)
throw new Error(`Crypto key should decode to ${sodium.crypto_secretbox_KEYBYTES} bytes in length`)
} catch(error) {
throw new Error('Missing or invalid options.crypto_key', error)
}
opts.encode = encode
opts.decode = decode
app.use(session(app, opts))
function encode(body) {
try {
body = JSON.stringify(body)
const plainbuf = new Buffer(body)
const cipherbuf = encrypt(plainbuf, secret)
// console.log(`crypto-session:${cipherbuf.toString('base64')}`)
return `crypto-session:${cipherbuf.toString('base64')}`
} catch(err) {
console.error('@steem/crypto-session: encode error resetting session', body, err, (err ? err.stack : undefined));
return encrypt(new Buffer('').toString('base64'), secret);
}
}
function decode(text) {
try {
if(!/^crypto-session:/.test(text))
throw 'Unrecognized encrypted session format.'
text = text.substring('crypto-session:'.length)
const buf = new Buffer(text, 'base64')
const body = decrypt(buf, secret).toString('utf8')
const json = JSON.parse(body)
// check if the cookie is expired
if (!json._expire) return null
if (json._expire < Date.now()) return null
return json
} catch(err) {
console.log(err)
try {
const jsonString = new Buffer(text, 'base64').toString('utf8')
JSON.parse(jsonString)
// Already JSON
console.log('@steem/crypto-session: Encrypting plaintext session.', jsonString)
return text
} catch(error2) {// debug('decode %j error: %s', json, err);
throw new Error('@steem/crypto-session: Discarding session: ' + text)
}
console.error('@steem/crypto-session: decode error resetting session', text, err, (err ? err.stack : undefined));
return {};
}
}
}
/**
@arg {Buffer} buf
@return {Buffer}
*/
function encrypt(buf, secret) {
const nonce = Buffer.from(sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES))
const ciphertext = sodium.crypto_secretbox_easy(buf, nonce, secret)
return Buffer.concat([nonce, Buffer.from(ciphertext)])
}
/**
@arg {Buffer} buf
@return Buffer
*/
function decrypt(buf, secret) {
const nonce = buf.slice(0, sodium.crypto_box_NONCEBYTES);
const cipherbuf = buf.slice(sodium.crypto_box_NONCEBYTES);
return sodium.crypto_secretbox_open_easy(cipherbuf, nonce, secret, 'text');
}