Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add express-session dependency #1341

Merged
merged 29 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fac787f
add express-session dep
awidener3 Dec 20, 2023
eaa9675
move session config into json, add config log
awidener3 Jan 2, 2024
f004907
update changelog and readme
awidener3 Jan 3, 2024
b1420c6
update test sample data
awidener3 Jan 3, 2024
dc1ac3f
remove print flag
awidener3 Jan 5, 2024
136e9cf
update express-session setup
awidener3 Jan 19, 2024
f5596ab
certs moved to json file in certs folder
awidener3 Jan 19, 2024
484a67c
update test sample config
awidener3 Jan 19, 2024
789d5f4
add todos
awidener3 Jan 23, 2024
bde599a
move session secret to separate generator
awidener3 Jan 23, 2024
87631d9
secret folder is now configurable
awidener3 Jan 23, 2024
95a6231
fix tests
awidener3 Jan 23, 2024
2cbee09
add new generateSecrets
awidener3 Jan 24, 2024
0cd1c87
remove secrets
awidener3 Jan 24, 2024
22e7bd2
save progress
awidener3 Jan 24, 2024
fdcb6ce
updates
awidener3 Jan 24, 2024
df8fa8f
secretsFolder to secretsDir
awidener3 Jan 25, 2024
88b0b19
remove generateSecrets, update other generators
awidener3 Jan 25, 2024
3f7c24a
update generators
awidener3 Jan 25, 2024
20c7e2a
update tests
awidener3 Jan 25, 2024
f71222d
fix undefined folder creation
awidener3 Jan 25, 2024
8a95361
updates to secrets folder
awidener3 Jan 25, 2024
13848bb
update readme instructions
awidener3 Jan 25, 2024
f73db3d
update changelog, readme
awidener3 Jan 25, 2024
81fd585
fix https tests
awidener3 Jan 25, 2024
dae3575
update readme
awidener3 Jan 26, 2024
4e02b94
update readme
awidener3 Jan 26, 2024
89535d5
fix tests
awidener3 Jan 26, 2024
c0ed331
fix other skipped test
awidener3 Jan 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Next version

- Put your changes here...
- Add `express-session` dependency.
- The name of the directory containing secrets and HTTPS keys is now configurable using the `secretsDir` parameter (default value is `secrets`).

## 0.21.15

Expand Down
43 changes: 40 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ Roosevelt apps created with the app generator come with the following notable [n
- Default shorthand:
- `npm run c`
- Script is short for: `node ./node_modules/roosevelt/lib/scripts/certsGenerator.js`
- `npm run generate-session-secret`: Generates a secret key for the `express-session` module.
- Script is short for: `node ./node_modules/roosevelt/lib/scripts/sessionSecretGenerator.js`
- `npm run generate-secrets`: Generates self-signed HTTPS certs and a `express-session` secret.
- `npm run audit-config`: Scans current `rooseveltConfig` and `scripts` in `package.json` and warns about any parameters or npm scripts that don't match the current Roosevelt API:
- Default shorthand:
- `npm run a`
Expand All @@ -200,11 +203,11 @@ Roosevelt apps created with the app generator come with the following notable [n
- `node app.js --build`: Only runs the build scripts and doesn't start the app.
- Default shorthands:
- `-b`
- `node app.js --webpack=verbose`: Enables webpack to print verbose errors to the console.
- `node app.js --webpack=verbose`: Enables webpack to print verbose errors to the console.
- Default shorthands:
- `--wp=verbose`
- `-w=verbose`
- `node app.js --webpack=verbose-file`: Enables webpack to print verbose errors to the console as well as write a webpackError file to the app's root directory containing the full error.
- `node app.js --webpack=verbose-file`: Enables webpack to print verbose errors to the console as well as write a webpackError file to the app's root directory containing the full error.
- Default shorthands:
- `--wp=verbose-file`
- `-w=verbose-file`
Expand Down Expand Up @@ -380,6 +383,12 @@ Resolves to:

- Default: *[String]* The directory where your app's `package.json` is located.

- `secretsDir`: Directory that stores certs, keys, and secrets.

- Default: *[String]* `secrets`.

- Important: Changing this value will require updating `.gitignore`.

- `localhostOnly`: Listen only to requests coming from localhost in production mode. This is useful in environments where it is expected that HTTP requests to your app will be proxied through a more traditional web server like Apache or nginx.

- Default: *[Boolean]* `true`.
Expand Down Expand Up @@ -475,6 +484,33 @@ Resolves to:
- Default: *[Object]*
The default options are specified in the [helmet docs](https://helmetjs.github.io/), with the exception of the upgrade-insecure-requests in the content security policy, which has been removed.

- `expressSession`: Parameter(s) to pass to the [express-session](https://github.com/expressjs/session) module. Can pass in a boolean (`true`/`false`), or supplying an object that allows further configuration using express-session parameters.

- Default: *[Boolean]* `true`

- If `expressSession` is set to `true`, it will use the configuration below:

```json
{
"resave": false,
"saveUninitialized": false,
}
```

- Optional: An object containing parameters that are specified in the [express-session docs](https://github.com/expressjs/session?tab=readme-ov-file#api) (Note: `secret` is generated by Roosevelt).

```json
// using true/false
"expressSession": true

// using express-session parameters
"expressSession:" {
"resave": false,
"saveUninitialized": false,
...other express-session parameters
}
```

- `toobusy`: Parameters to pass to the [node-toobusy](https://github.com/STRML/node-toobusy) module.

- `maxLagPerRequest`: *[Number]* Maximum amount of time (in milliseconds) a given request is allowed to take before being interrupted with a [503 error](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors).
Expand Down Expand Up @@ -831,7 +867,7 @@ Resolves to:
etc...
]
```

- `verbose`: *[string]* Enable Webpack verbose error handler.

- Default: *[Object]*
Expand Down Expand Up @@ -1287,6 +1323,7 @@ In addition to exposing a number of variables to Express and providing the MVC i

- Includes the [compression](https://github.com/expressjs/compression) middleware.
- Includes the [cookie-parser](https://github.com/expressjs/cookie-parser) middleware.
- Includes the [express-session](https://github.com/expressjs/session) middleware.
- Includes the [helmet](https://github.com/helmetjs/helmet) middleware.
- Logs HTTP requests to the console using [morgan](https://github.com/expressjs/morgan), specifically `morgan('combined')`.
- Includes the [method-override](https://github.com/expressjs/method-override) middleware.
Expand Down
2 changes: 2 additions & 0 deletions lib/defaults/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
"requestCert": null,
"rejectUnauthorized": null
},
"expressSession": true,
"secretsDir": "secrets",
"modelsPath": "mvc/models",
"viewsPath": "mvc/views",
"viewEngine": "none",
Expand Down
30 changes: 18 additions & 12 deletions lib/scripts/certsGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
} else {
certsGenerator()
}
function certsGenerator (appDir) {

function certsGenerator (appDir, keyFolder) {

Check warning on line 9 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L9

Added line #L9 was not covered by tests
const selfsigned = require('selfsigned')
const pem = selfsigned.generate(null, {
keySize: 2048, // the size for the private key in bits (default: 1024)
Expand All @@ -20,32 +21,37 @@
const fs = require('fs')
const key = pem.private
const cert = pem.cert
const keyFolder = './certs'
const path = require('path')
const sourceParams = require('../sourceParams')

Check warning on line 25 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L25

Added line #L25 was not covered by tests

if (!appDir) {
let processEnv
if (fs.existsSync(path.join(process.cwd(), 'node_modules')) === false) {
processEnv = process.cwd()
} else {
processEnv = undefined
}
const processEnv = fs.existsSync(path.join(process.cwd(), 'node_modules'))
? process.cwd()
: undefined

Check warning on line 31 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L28-L31

Added lines #L28 - L31 were not covered by tests
appDir = processEnv
}

if (!keyFolder) {
const params = sourceParams({ appDir: process.cwd() })
keyFolder = params.secretsDir
}

Check warning on line 39 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L35-L39

Added lines #L35 - L39 were not covered by tests
try {
if (!fs.existsSync(keyFolder)) {
fs.mkdirSync(keyFolder)
// make secrets folder if non-existent
if (!fs.existsSync(appDir + '/' + keyFolder)) {
const path = appDir + '/' + keyFolder
fs.mkdirSync(path)

Check warning on line 44 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L41-L44

Added lines #L41 - L44 were not covered by tests
}

fs.writeFileSync('./certs/key.pem', key, err => {
fs.writeFileSync(keyFolder + '/key.pem', key, err => {

Check warning on line 47 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L47

Added line #L47 was not covered by tests
if (err) {
console.error(err)
}
// file written successfully
})

fs.writeFileSync('./certs/cert.pem', cert, err => {
fs.writeFileSync(keyFolder + '/cert.pem', cert, err => {

Check warning on line 54 in lib/scripts/certsGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/certsGenerator.js#L54

Added line #L54 was not covered by tests
if (err) {
console.error(err)
}
Expand Down
6 changes: 6 additions & 0 deletions lib/scripts/configAuditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ function configAudit (appDir) {
case 'modelsPath':
checkTypes(userParam, key, ['string'])
break
case 'secretsDir':
checkTypes(userParam, key, ['string'])
break
case 'formidable':
checkTypes(userParam, key, ['boolean', 'object'])
break
Expand Down Expand Up @@ -252,6 +255,9 @@ function configAudit (appDir) {
case 'helmet':
checkTypes(userParam, key, ['object'])
break
case 'expressSession':
checkTypes(userParam, key, ['boolean', 'object'])
break
case 'bodyParser': {
checkTypes(userParam, key, ['object'])
const bodyParserParam = userParam || {}
Expand Down
44 changes: 44 additions & 0 deletions lib/scripts/sessionSecretGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
if (module.parent) {
module.exports = {
sessionSecretGenerator
}
} else {
sessionSecretGenerator()
}

Check warning on line 7 in lib/scripts/sessionSecretGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/sessionSecretGenerator.js#L6-L7

Added lines #L6 - L7 were not covered by tests

function sessionSecretGenerator (appDir, keyFolder) {
const crypto = require('crypto')
const fs = require('fs')
const path = require('path')
const sourceParams = require('../sourceParams')

if (!appDir) {
const processEnv = fs.existsSync(path.join(process.cwd(), 'node_modules'))
? process.cwd()
: undefined

appDir = processEnv
}

if (!keyFolder) {
const params = sourceParams({ appDir: process.cwd() })
keyFolder = params.secretsDir
}

try {
// make secrets folder if non-existent
if (!fs.existsSync(appDir + '/' + keyFolder)) {
const path = appDir + '/' + keyFolder
fs.mkdirSync(path)
}

fs.writeFileSync(keyFolder + '/sessionSecret.json', JSON.stringify({
secret: crypto.randomUUID()
}), err => {
if (err) {
console.error(err)
}
// file written successfully

Check warning on line 41 in lib/scripts/sessionSecretGenerator.js

View check run for this annotation

Codecov / codecov/patch

lib/scripts/sessionSecretGenerator.js#L38-L41

Added lines #L38 - L41 were not covered by tests
})
} catch {}
}
26 changes: 25 additions & 1 deletion lib/setExpressConfigs.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// configure specific express options

const fs = require('fs')
require('@colors/colors')

const morgan = require('morgan') // express logger
const express = require('express')
const session = require('express-session')
const helmet = require('helmet')

module.exports = function (app) {
Expand Down Expand Up @@ -45,6 +46,29 @@
// set morgan
app.set('morgan', morgan)

// enable express-session
if (params.expressSession) {
const secret = JSON.parse(fs.readFileSync(params.secretsDir + '/sessionSecret.json', 'utf-8')).secret

if (typeof params.expressSession === 'boolean') {
// user wants default config
app.use(session({
// used to sign the session ID cookie
secret,
// setting to true forces the session to be saved to the session store even if session wasn't modified during the request
resave: false,
// setting to true forces an "uninitialized" session to be saved to the store - a session is "uninitialized" when it is new but not modified
saveUninitialized: false
}))
} else {
// user has supplied their own configuration
app.use(session({
...params.expressSession,
secret // generate an express session key
}))
}

Check warning on line 69 in lib/setExpressConfigs.js

View check run for this annotation

Codecov / codecov/patch

lib/setExpressConfigs.js#L64-L69

Added lines #L64 - L69 were not covered by tests
}

// set helmet middleware
if (params.mode !== 'development') {
let contentSecurityPolicy = params.helmet.contentSecurityPolicy
Expand Down
8 changes: 7 additions & 1 deletion lib/sourceParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ module.exports = (params, app, appSchema) => {
*/
const schema = {
appDir: {
default: params.appDir
default: appDir
},
port: {
envVar: ['HTTP_PORT', 'NODE_PORT'],
Expand Down Expand Up @@ -155,6 +155,9 @@ module.exports = (params, app, appSchema) => {
helmet: {
default: defaults.helmet
},
expressSession: {
default: defaults.expressSession
},
bodyParser: {
urlEncoded: {
default: defaults.bodyParser.urlEncoded
Expand Down Expand Up @@ -214,6 +217,9 @@ module.exports = (params, app, appSchema) => {
default: null
}
},
secretsDir: {
default: defaults.secretsDir
},
modelsPath: {
default: defaults.modelsPath
},
Expand Down
65 changes: 65 additions & 0 deletions package-lock.json

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

Loading
Loading