Skip to content

Commit 734aefb

Browse files
committed
Tons of tweaks / finishing up.
1 parent cdbc04e commit 734aefb

File tree

128 files changed

+7547
-1456
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+7547
-1456
lines changed

.dockerignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ config/local.js
77
.editorconfig
88
.eslintignore
99
.eslintrc
10-
.mocharc.yaml
10+
.mocharc.yml
1111
.nycrc
1212
.tmp
1313
.travis.yml
1414
test
1515

16-
README.md
16+
**/README*
1717
CHANGELOG.md
1818
LICENSE

.idea/dictionaries/neonexusdemortis.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations/Start_Ngrok.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

.npmrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ loglevel=error
99

1010
# Make "npm audit" an opt-in thing for subsequent installs within this app:
1111
audit=true
12+
13+
# Don't install optional dependencies automatically (which is a weird default NPM...):
14+
omit=optional

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
# Changelog
22

3-
## [v4.2.0](https://github.com/neonexus/sails-react-bootstrap-webpack/compare/v4.1.1...v4.2.0) (2023-03-19)
3+
## [v4.2.0](https://github.com/neonexus/sails-react-bootstrap-webpack/compare/v4.1.1...v4.2.0) (2023-04-20)
44
### Features
55

6+
* Built a script for [`Ngrok`](https://www.npmjs.com/package/ngrok), which will build assets, start Sails, and create an Ngrok tunnel (to the configured PORT).
67
* Built 2FA (2-Factor Authentication) capabilities.
8+
* Added `appName` as a config option.
79
* Added `createdBy` to the [`User`](api/models/User.js) model.
10+
* Added [`sails-hook-autoreload`](https://www.npmjs.com/package/sails-hook-autoreload) support (must manually install).
811
* Built session expiration handling.
912
* Built password changing modal / API.
1013
* Made session data saving automatic, and work with both sessions / API tokens.
1114
* Fixed some README quirks.
15+
* Removed unneeded React imports (because of the Babel transform). For more info, [read this announcement (from 2020...)](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html).
1216
* Updated React links to use their new domain.
17+
* Removed `serve-static` in favor of `express.static`.
1318
* Updated dependencies.
1419

1520
### Breaking Changes
1621

1722
* Moved CSRF secret storage from the `data` column, to its own column, so it can easily be encrypted/decrypted in the [`Session`](api/models/Session.js) model.
18-
* Changed how API tokens are handled. So now, when using an API token, the ID must be given first, then the token, seperated by a colon.<br />Example: `Authorization` header is: `tokenID:apiToken` (or `Bearer tokenID:apiToken`).
23+
* Changed how API tokens are handled. So now, when using an API token, the ID must be given first, then the token, seperated by a colon.<br />Example: `Authorization` header is: `tokenID:apiToken` (or `Bearer tokenID:apiToken`). This is because `token` is now an encrypted column.
1924
* Renamed `sails.helpers.updateCsrf` -> `sails.helpers.updateCsrfAndExpiry` to reflect the session expiry update.
25+
* Renamed `req.requestId`/`env.req.requestId` -> `req.id`/`env.req.id` to better match general convention.
26+
* Renamed `process.env` -> `appConfig` in the Webpack config (a variable used to pass data down to the frontend). What was I doing?!...
2027

2128
## [v4.1.1](https://github.com/neonexus/sails-react-bootstrap-webpack/compare/v4.1.0...v4.1.1) (2023-03-14)
2229
### Features

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:18.15
1+
FROM node:18.16
22
MAINTAINER NeoNexus DeMortis
33

44
RUN mkdir /var/www && mkdir /var/www/myapp

README.md

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,34 @@ Gitter: [![Join the chat at https://gitter.im/sails-react-bootstrap-webpack/comm
1414
* [Main Features](#main-features)
1515
* [Branch Warning](#branch-warning)
1616
* [Current Dependencies](#current-dependencies)
17+
* [Optional Dependencies](#optional-dependencies)
1718
* [How to Use](#how-to-use)
1819
* [Configuration](#configuration)
19-
* [Custom Configuration Options](#custom-configuration-options)
20-
* [Want to configure the `X-Powered-By` header?](#want-to-configure-the--x-powered-by--header)
20+
* [Custom Configuration Options](#custom-configuration-options)
21+
* [Want to configure the `X-Powered-By` header?](#want-to-configure-the-x-powered-by-header)
2122
* [Scripts Built Into `package.json`](#scripts-built-into-packagejson)
2223
* [Sails Scripts](#sails-scripts)
2324
* [Environment Variables](#environment-variables)
2425
* [Request Logging](#request-logging)
2526
* [Using Webpack](#using-webpack)
26-
* [Local Dev](#local-dev)
27-
* [Remote Builds](#remote-builds)
28-
* [Configuration](#configuration-1)
27+
* [Local Dev](#local-dev)
28+
* [Remote Builds](#remote-builds)
29+
* [Configuration](#configuration-1)
2930
* [Building with React](#building-with-react)
30-
* [Serving Compiled Assets](#serving-compiled-assets)
31+
* [Serving Compiled Assets](#serving-compiled-assets)
3132
* [Schema Validation and Enforcement](#schema-validation-and-enforcement)
32-
* [If you DO NOT want schema validation](#if-you-do-not-want-schema-validation)
33+
* [If you DO NOT want schema validation](#if-you-do-not-want-schema-validation)
3334
* [PwnedPasswords.com Integration](#pwnedpasswordscom-integration)
35+
* [Working With Ngrok](#working-with-ngrok)
36+
* [First Thing's First](#first-things-first)
37+
* [Script Options](#script-options)
38+
* [Support for `sails-hook-autoreload`](#support-for-sails-hook-autoreload)
3439
* [What About SEO?](#what-about-seo)
3540
* [Useful Links](#useful-links)
3641

3742
## Main Features
3843

44+
* Online in a single command, thanks to included [Ngrok support](#working-with-ngrok).
3945
* Automatic (incoming) request logging (manual outgoing), via Sails models / hooks.
4046
* Setup for Webpack auto-reload dev server.
4147
* Setup so Sails will serve Webpack-built bundles as separate apps (so, a marketing site, and an admin site can live side-by-side).
@@ -46,7 +52,7 @@ Gitter: [![Join the chat at https://gitter.im/sails-react-bootstrap-webpack/comm
4652
feature inside [`config/bootstrap.js`](config/bootstrap.js). See [schema validation and enforcement](#schema-validation-and-enforcement) for more info.
4753
* New passwords will be checked against the [PwnedPasswords API](https://haveibeenpwned.com/API/v3#PwnedPasswords). If there is a single hit for the password, an error will be given, and the user will
4854
be forced to choose another. See [PwnedPasswords integration](#pwnedpasswordscom-integration) for more info.
49-
* Google Authenticator-style OTP (One-Time Password) functionality.
55+
* Google Authenticator-style OTP (One-Time Password) functionality; also known as 2FA (2-Factor Authentication).
5056

5157
## Branch Warning
5258

@@ -66,13 +72,21 @@ the [`releases section`](https://github.com/neonexus/sails-react-bootstrap-webpa
6672
* [React-Bootstrap](https://react-bootstrap.github.io) **v2**
6773
* [Webpack](https://webpack.js.org) **v5**
6874

75+
### Optional Dependencies
76+
77+
Optional dependencies are not automatically installed in this repo. You must either manually install them with `npm i`, or you can install all optional dependencies: `npm i --include=optional`.
78+
79+
There are currently 2 optional dependencies in this repo: [`ngrok`](#working-with-ngrok) and [`sails-hook-autoreload`](#support-for-sails-hook-autoreload).
80+
6981
See the [`package.json` for more details](package.json).
7082

7183
## How to Use
7284

7385
This repo is not installable via `npm`. Instead, GitHub provides a handy "Use this template" (green) button at the top of this page. That will create a special clone of this repo (so there is a single,
7486
init commit, instead of the commit history from this repo).
7587

88+
Or, you can download a copy of the [latest release](https://github.com/neonexus/sails-react-bootstrap-webpack/releases/latest).
89+
7690
## Configuration
7791

7892
In the `config` folder, there is the [`local.js.sample`](config/local.js.sample) file, which is meant to be copied to `local.js`. This file (`local.js`, not the sample) is ignored by Git, and intended
@@ -93,37 +107,53 @@ option. If the option path is `sails.config.security.checkPwnedPasswords`, then
93107
}
94108
```
95109

96-
... to your `config/local.js` to overwrite the option on your local machine only.
110+
... to your `config/local.js` to overwrite any option on your local machine only.
97111

98112
<table>
99113
<thead>
100114
<tr>
101115
<th>Option Name (<code>sails.config.</code>)</th>
102-
<th>Initially Defined In</th>
116+
<th>Found In (<code>config/</code>)</th>
103117
<th>Default</th>
104118
<th>Description</th>
105119
</tr>
106120
</thead>
107121
<tbody>
122+
<tr>
123+
<td><code>appName</code></td>
124+
<td>
125+
<code>local.js</code><br />
126+
<a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/env/development.js"><code>env/development.js</code></a><br />
127+
<a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/env/production.js"><code>env/production.js</code></a><br />
128+
</td>
129+
<td>
130+
<code>My&nbsp;App&nbsp;(LOCAL)</code><br />
131+
<code>My App (DEV)</code><br />
132+
<code>My App</code>
133+
</td>
134+
<td>
135+
The general name to use for this app.
136+
</td>
137+
</tr>
108138
<tr>
109139
<td><code>models.validateOnBootstrap</code></td>
110-
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/bootstrap.js"><code>config/bootstrap.js</code></a></td>
140+
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/bootstrap.js"><code>bootstrap.js</code></a></td>
111141
<td><code>true</code></td>
112142
<td>When enabled, and <code>models.migrate === 'safe'</code> (aka PRODUCTION), then the SQL schemas of the default datastore will be validated against the model definitions. <br><br>See <a href="#schema-validation-and-enforcement">schema validation and enforcement</a> for more info.</td>
113143
</tr>
114144
<tr>
115145
<td><code>security.checkPwnedPasswords</code></td>
116-
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/security.js"><code>config/security.js</code></a></td>
146+
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/security.js"><code>security.js</code></a></td>
117147
<td><code>true</code></td>
118-
<td>When enabled, <a href="/neonexus/sails-react-bootstrap-webpack/blob/release/api/helpers/is-password-valid.js"><code>sails.helpers.isPasswordValid()</code></a> will run it's normal checks, before checking with the PwnedPasswords.com API to verify the password has not been found in a known security breach. If it has, it will consider the password invalid.</td>
148+
<td>When enabled, <a href="/neonexus/sails-react-bootstrap-webpack/blob/release/api/helpers/is-password-valid.js"><code>sails.helpers.isPasswordValid()</code></a> will run its normal checks, before checking with the PwnedPasswords.com API to verify the password has not been found in a known security breach. If it has, it will consider the password invalid.</td>
119149
</tr>
120150
<tr>
121151
<td>
122152
<code>security.</code><br/>
123-
<code>requestLogger.</code><br/>
124-
<code>logSensitiveData</code>
153+
&nbsp;&nbsp;&nbsp;&nbsp;<code>requestLogger.</code><br/>
154+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code>logSensitiveData</code>
125155
</td>
126-
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/security.js"><code>config/security.js</code></a> <br> <a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/env/development.js"><code>config/env/development.js</code></a> <br> <a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/env/production.js"><code>config/env/production.js</code></a></td>
156+
<td><a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/security.js"><code>security.js</code></a> <br> <a href="/neonexus/sails-react-bootstrap-webpack/blob/release/config/env/development.js"><code>env/development.js</code></a></td>
127157
<td><code>false</code></td>
128158
<td>If enabled, and NOT a PRODUCTION environment, the <a href="#request-logging">request logger</a> will log sensitive info, such as passwords. <br><br> This will ALWAYS be false on PRODUCTION. It is in the PRODUCTION configuration file only as a reminder.</td>
129159
</tr>
@@ -206,7 +236,7 @@ This does require you either have Sails installed globally, or you have `node_mo
206236
</tr>
207237
<tr>
208238
<td><pre><code>sails run lines</code></pre></td>
209-
<td>Will count the lines of code in the project, minus <code>.gitignore</code>'d files, for funzies. There are currently about 9k custom lines in this repo (views, controllers, helpers, hooks, etc); a small drop in the bucket, compared to what it's built on.
239+
<td>Will count the lines of code in the project, minus <code>.gitignore</code>'d files, for funzies. There are currently about 7k custom lines in this repo (views, controllers, helpers, hooks, etc); a small drop in the bucket, compared to what it's built on.
210240
</td>
211241
</tr>
212242
<tr>
@@ -252,6 +282,7 @@ and [`config/env/production.js`](config/env/production.js)
252282
| `DB_PORT` | 3306 | The port number for the datastore. |
253283
| `DB_SSL` | true | If the datastore requires SSL, set this to "true". |
254284
| `SESSION_SECRET` | "" (empty string) | Used to sign cookies, and SHOULD be set, especially on PRODUCTION environments. |
285+
| `NGROK_AUTH` | "" (empty string) | Ngrok auth token used in the [`ngrok.js`](#working-with-ngrok) script. |
255286

256287
[//]: # (| DATA_ENCRYPTION_KEY | "" &#40;empty string&#41; | **DATA_ENCRYPTION_KEY** | **"" &#40;empty string&#41;** | **Currently unused; intended for future use.** |)
257288

@@ -329,6 +360,35 @@ This functionality is turned on by default, and can be shutoff per-use, or globa
329360
option set to `true`, to disable the check per use (see [`api/controllers/common/login.js`](api/controllers/common/login.js#L40) for example). Inside of [`config/security.js`](config/security.js), the
330361
variable `checkPwnedPasswords` can be set to `false` to disable it globally.
331362

363+
## Working With Ngrok
364+
365+
This repo has a custom script ([`ngrok.js`](ngrok.js)), which will start an Ngrok tunnel (using the NPM package [`ngrok`](https://npmjs.com/package/ngrok)), build assets, and start Sails.
366+
367+
### First thing's first
368+
369+
You will want to get an auth token (and create an account if you haven't already): https://dashboard.ngrok.com/tunnels/authtokens
370+
371+
You will need to `npm i ngrok --save-dev` (or install optional dependencies) before you can do anything. I've opted to not have it pre-installed, as it does add a bit of bloat, and not everyone is going to use it.
372+
373+
After you have it installed, you can run `ngrok.js`, like this: `node ngrok`.
374+
375+
### Script Options
376+
377+
These are the current configuration flags. Order does not matter. There will likely be more in the future.
378+
379+
| Option | Description |
380+
|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
381+
| `nobuild` | Adding this flag will disable asset building. |
382+
| `auth=TOKEN` | Adding this flag (replacing TOKEN with your actual token) will set your Ngrok auth token. In most cases, ngrok will automatically save this token in your home folder, and re-use it later. You can test this out by omitting your token on next run, and go to your [Ngrok dashboard](https://dashboard.ngrok.com/tunnels/agents). |
383+
384+
You can also use the environment variable `NGROK_AUTH` to pass your auth token.
385+
386+
Full example: `node ngrok nobuild auth=S1T2A3Y4I5N6G7A8L9I0V1E`
387+
388+
## Support for `sails-hook-autoreload`
389+
390+
If you would like to use [`sails-hook-autoreload`](https://npmjs.com/package/sails-hook-autoreload), just install it: `npm i sails-hook-autoreload --save-dev` (or install optional dependencies). The config file [`config/autoreload.js`](config/autoreload.js) is already pre-configured for this repo.
391+
332392
## What about SEO?
333393

334394
I recommend looking at [prerender.io](https://prerender.io). They offer a service (free up to 250 pages) that caches the end result of a JavaScript-rendered view (React, Vue, Angular), allowing search

api/controllers/admin/create-api-token.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
friendlyName: 'Create API Token',
33

4-
description: 'Get an API token, which replaces CSRF token / session cookie usage.',
4+
description: 'Create an API token, which replaces CSRF token / session cookie usage.',
55

66
inputs: {},
77

@@ -19,11 +19,11 @@ module.exports = {
1919
data: {} // Used to store things that are temporary, or only apply to this session.
2020
}).fetch().decrypt();
2121

22+
const outToken = newToken.id + ':' + newToken.token;
23+
2224
return exits.created({
23-
id: newToken.id,
24-
token: newToken.token,
25-
header: 'Bearer ' + newToken.id + ':' + newToken.token,
26-
__skipCSRF: true // this tells our "created" response to ignore the CSRF token update
25+
token: outToken,
26+
header: 'Bearer ' + outToken
2727
});
2828
}
2929
};

api/controllers/common/disable-2fa.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module.exports = {
2+
friendlyName: 'Disable 2-Factor Authentication',
3+
4+
description: 'Disable 2-factor authentication for the current user.',
5+
6+
inputs: {
7+
password: {
8+
type: 'string',
9+
required: true
10+
},
11+
12+
otp: {
13+
type: 'string',
14+
minLength: 6,
15+
maxLength: 8,
16+
allowNull: false,
17+
required: true
18+
}
19+
},
20+
21+
exits: {
22+
ok: {
23+
responseType: 'ok'
24+
},
25+
badRequest: {
26+
responseType: 'badRequest'
27+
}
28+
},
29+
30+
fn: async (inputs, exits, env) => {
31+
const foundUser = await sails.models.user.findOne(env.req.session.user.id);
32+
33+
if (!sails.models.user.doPasswordsMatch(inputs.password, foundUser.password)) {
34+
return exits.badRequest('Password is invalid.');
35+
}
36+
37+
const isValidOTP = await sails.helpers.verifyAndSpendOtp(env.req.session.user.id, inputs.otp);
38+
39+
if (typeof isValidOTP === 'string') {
40+
return exits.badRequest('Invalid one-time password / backup code.');
41+
}
42+
43+
// Should not happen... But might
44+
if (!isValidOTP) {
45+
return exits.badRequest('2-factor authentication is not enabled.');
46+
}
47+
48+
const foundOTP = await sails.models.otp.findOne({user: env.req.session.user.id, isEnabled: true});
49+
50+
await sails.models.otp.update(foundOTP.id).set({isEnabled: false});
51+
52+
return exits.ok();
53+
}
54+
};

0 commit comments

Comments
 (0)