Skip to content

Commit

Permalink
Revert "fix: monitor objects and delete property (#218)"
Browse files Browse the repository at this point in the history
This reverts commit d79111c.
  • Loading branch information
mcollina committed Apr 10, 2024
1 parent d79111c commit ca28d71
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 221 deletions.
110 changes: 33 additions & 77 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,39 @@ const sodium = require('sodium-native')
const kObj = Symbol('object')
const kCookieOptions = Symbol('cookie options')

// allows us to use property getters and setters as well as get and set methods on session object
const sessionProxyHandler = {
get (target, prop) {
// Calling functions eg request[sessionName].get('key') or request[sessionName].set('key', 'value')
if (typeof target[prop] === 'function') {
return new Proxy(target[prop], {
apply (applyTarget, thisArg, args) {
return Reflect.apply(applyTarget, target, args)
}
})
}

// accessing own properties, eg request[sessionName].changed
if (Object.prototype.hasOwnProperty.call(target, prop)) {
return target[prop]
}

// accessing session property
return target.get(prop)
},
set (target, prop, value) {
// modifying own properties, eg request[sessionName].changed
if (Object.prototype.hasOwnProperty.call(target, prop)) {
target[prop] = value
return true
}

// modifying session property
target.set(prop, value)
return true
}
}

function fastifySecureSession (fastify, options, next) {
if (!Array.isArray(options)) {
options = [options]
Expand Down Expand Up @@ -101,9 +134,6 @@ function fastifySecureSession (fastify, options, next) {
}
}

const sessionProxyCache = new WeakMap()
const sessionProxyHandler = createSessionProxyHandler(sessionProxyCache)

fastify.decorate('decodeSecureSession', (cookie, log = fastify.log, sessionName = defaultSessionName) => {
if (cookie === undefined) {
// there is no cookie
Expand Down Expand Up @@ -296,80 +326,6 @@ class Session {
}
}

function createSessionProxyHandler (sessionProxyCache) {
function createObjectProxyHandler (sessionTarget) {
return {
get (target, prop, receiver) {
const value = Reflect.get(target, prop, receiver)
if (typeof value === 'object' && value !== null) {
if (sessionProxyCache.has(value)) {
return sessionProxyCache.get(value)
}
const proxy = new Proxy(value, createObjectProxyHandler(sessionTarget))
sessionProxyCache.set(value, proxy)
return proxy
}
return value
},
set (target, prop, value, receiver) {
sessionTarget.touch()
return Reflect.set(target, prop, value, receiver)
},
deleteProperty (target, prop) {
sessionTarget.touch()
return Reflect.deleteProperty(target, prop)
}
}
}

// allows us to use property getters and setters as well as get and set methods on session object
return {
get (target, prop) {
// Calling functions eg request[sessionName].get('key') or request[sessionName].set('key', 'value')
if (typeof target[prop] === 'function') {
return new Proxy(target[prop], {
apply (applyTarget, thisArg, args) {
return Reflect.apply(applyTarget, target, args)
}
})
}

// Accessing instances to objects within session will be proxied and update session object
if (typeof target[prop] === 'object' && target[prop] !== null) {
if (sessionProxyCache.has(target[prop])) {
return sessionProxyCache.get(target[prop])
}
const proxy = new Proxy(target[prop], createObjectProxyHandler(target))
sessionProxyCache.set(target[prop], proxy)
return proxy
}

// accessing own properties, eg request[sessionName].changed
if (Object.prototype.hasOwnProperty.call(target, prop)) {
return target[prop]
}

// accessing session property
return target.get(prop)
},
set (target, prop, value) {
// modifying own properties, eg request[sessionName].changed
if (Object.prototype.hasOwnProperty.call(target, prop)) {
target[prop] = value
return true
}

// modifying session property
target.set(prop, value)
return true
},
deleteProperty (target, prop) {
target.touch()
return Reflect.deleteProperty(target, prop)
}
}
}

function genNonce () {
const buf = Buffer.allocUnsafe(sodium.crypto_secretbox_NONCEBYTES)
sodium.randombytes_buf(buf)
Expand Down
144 changes: 0 additions & 144 deletions test/access.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,150 +180,6 @@ t.test('session is changed', t => {
})
})

t.test('session is changed when property is modified using delete operator', t => {
t.plan(8)
const fastify = Fastify()
fastify.register(SecureSessionPlugin, {
key
})
t.teardown(fastify.close.bind(fastify))

fastify.post('/', (request, reply) => {
request.session.data1 = request.body
const changed = request.session.changed

if (!changed) {
reply.code(404).send()
return
}

reply.send(changed)
})

fastify.post('/delete', (request, reply) => {
delete request.session.data1
const changed = request.session.changed

if (!changed) {
reply.code(404).send()
return
}

reply.send(changed)
})

fastify.inject({
method: 'POST',
url: '/',
payload: {
some: 'data'
}
}, (error, response) => {
t.error(error)
t.equal(response.statusCode, 200)
t.ok(response.headers['set-cookie'])
t.same(JSON.parse(response.payload), true)

fastify.inject({
method: 'POST',
url: '/delete',
headers: {
cookie: response.headers['set-cookie']
}
}, (error, response) => {
t.error(error)
t.equal(response.statusCode, 200)
t.ok(response.headers['set-cookie'])
t.same(JSON.parse(response.payload), true)
})
})
})

t.test('session is changed when property is a nested object which is modified or deleted', t => {
t.plan(12)
const fastify = Fastify()
fastify.register(SecureSessionPlugin, {
key
})
t.teardown(fastify.close.bind(fastify))

fastify.post('/', (request, reply) => {
request.session.data1 = request.body
const changed = request.session.changed

if (!changed) {
reply.code(404).send()
return
}

reply.send(changed)
})

fastify.post('/modify', (request, reply) => {
request.session.data1.some.first = '2'
const changed = request.session.changed

if (!changed) {
reply.code(404).send()
return
}

reply.send(changed)
})

fastify.post('/delete', (request, reply) => {
delete request.session.data1.some.first
const changed = request.session.changed

if (!changed) {
reply.code(404).send()
return
}

reply.send(changed)
})

// handle modification of nested objects
fastify.inject({
method: 'POST',
url: '/',
payload: {
some: { first: '1' }
}
}, (error, response) => {
t.error(error)
t.equal(response.statusCode, 200)
t.ok(response.headers['set-cookie'])
t.same(JSON.parse(response.payload), true)

fastify.inject({
method: 'POST',
url: '/modify',
headers: {
cookie: response.headers['set-cookie']
}
}, (error, response) => {
t.error(error)
t.equal(response.statusCode, 200)
t.ok(response.headers['set-cookie'])
t.same(JSON.parse(response.payload), true)

fastify.inject({
method: 'POST',
url: '/delete',
headers: {
cookie: response.headers['set-cookie']
}
}, (error, response) => {
t.error(error)
t.equal(response.statusCode, 200)
t.ok(response.headers['set-cookie'])
t.same(JSON.parse(response.payload), true)
})
})
})
})

t.test('session is deleted', t => {
t.plan(5)
const fastify = Fastify()
Expand Down

0 comments on commit ca28d71

Please sign in to comment.